diff --git a/Aucma.Core.CodeBinding/ViewModels/IndexPageViewModel.cs b/Aucma.Core.CodeBinding/ViewModels/IndexPageViewModel.cs index 3cf647ec..e311d046 100644 --- a/Aucma.Core.CodeBinding/ViewModels/IndexPageViewModel.cs +++ b/Aucma.Core.CodeBinding/ViewModels/IndexPageViewModel.cs @@ -262,6 +262,8 @@ namespace Aucma.Core.CodeBinding.ViewModels } #region plc交互 + + private SemaphoreSlim semaphore = new SemaphoreSlim(0); /// /// 下发plc放行信号 /// @@ -280,6 +282,7 @@ namespace Aucma.Core.CodeBinding.ViewModels obj.plc.WriteInt32("D100", 1); // 等待plc反馈信号 waitPlcSignal(); + semaphore.Wait(); result = true; } else @@ -328,6 +331,10 @@ namespace Aucma.Core.CodeBinding.ViewModels Thread.Sleep(1000); } while (isFlag); + + // 释放信号量 + semaphore.Release(); + } else { diff --git a/Aucma.Core.ProductOffLine/Startup.cs b/Aucma.Core.ProductOffLine/Startup.cs index a8468c04..19d29bf5 100644 --- a/Aucma.Core.ProductOffLine/Startup.cs +++ b/Aucma.Core.ProductOffLine/Startup.cs @@ -7,6 +7,7 @@ using Admin.Core.Model; using Admin.Core.Repository; using Admin.Core.Service; using Admin.Core.Tasks; +using Aucma.Core.RunPlc; using Aucma.Core.Scanner; using Autofac; using Microsoft.AspNetCore.Builder; @@ -45,7 +46,7 @@ namespace Aucma.Core.ProductOffLine /// This method gets called by the runtime. Use this method to add services to the container. /// /// - public void ConfigureServices(IServiceCollection services) + public async void ConfigureServices(IServiceCollection services) { //Appsettings services.AddSingleton(new Appsettings(Configuration)); @@ -61,10 +62,15 @@ namespace Aucma.Core.ProductOffLine //עҵ AddServices(services); - // - services.AddJobSetup(); //ɨ services.AddScannerSetup(); + + // + // services.AddJobSetup(); + + //PLC + services.AddPlcSetup(); + //ֱ֧ȫ :֧ System.Text.Encoding.GetEncoding("GB2312") System.Text.Encoding.GetEncoding("GB18030") Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); } @@ -85,8 +91,7 @@ namespace Aucma.Core.ProductOffLine /// /// /// - public void Configure(IApplicationBuilder app, ISysTasksQzService tasksQzService, - ISchedulerCenter schedulerCenter, IScannerService scannerService) + public void Configure(IApplicationBuilder app, IScannerService scannerService, IRunPlcService runPlcService) { // ʹþ̬ļ app.UseStaticFiles(); @@ -94,9 +99,11 @@ namespace Aucma.Core.ProductOffLine //app.UseAuthorization(); // QuartzNetJobȷ - app.UseQuartzJobMildd(tasksQzService, schedulerCenter); + // app.UseQuartzJobMildd(tasksQzService, schedulerCenter); //ɨ app.UseScannerMildd(scannerService); + //PLC + app.UsePlcMildd(runPlcService); } #region ע diff --git a/Aucma.Core.ProductOffLine/ViewModels/IndexPageViewModel.cs b/Aucma.Core.ProductOffLine/ViewModels/IndexPageViewModel.cs index 15cc4167..bbc1fac9 100644 --- a/Aucma.Core.ProductOffLine/ViewModels/IndexPageViewModel.cs +++ b/Aucma.Core.ProductOffLine/ViewModels/IndexPageViewModel.cs @@ -14,6 +14,9 @@ using static Aucma.Core.Scanner.MvCodeHelper; using Admin.Core.Common; using System.Linq; using static Npgsql.Replication.PgOutput.Messages.RelationMessage; +using Aucma.Core.PLc; +using System.Threading.Tasks; +using Consul; /* * 成品分舵入库首页信息 @@ -24,15 +27,17 @@ namespace Aucma.Core.ProductOffLine.ViewModels public partial class IndexPageViewModel : ObservableObject { private static readonly log4net.ILog log = LogManager.GetLogger(typeof(IndexPageViewModel)); - + + public IndexPageViewModel() { MvCodeHelper.ReceiveCodeEvent += ReceiveCode; + // test(); //List listdatabase = Appsettings.app("DBS") // .Where(i => i.Enabled).ToList(); - InitEveryDayMethod(); - + InitEveryDayMethod(); + test2(); } #region 扫描信息 @@ -207,15 +212,22 @@ namespace Aucma.Core.ProductOffLine.ViewModels private void ReceiveCode(string code,int direction) { //1.扫描的SN条码去条码系统查询GET_BARCODE_DATA + string result = "Y@1104@16160030000000910780@000010034895@@ @000000@000000009000000807@BCD-160C,家电下乡@@BCD-160C@皓月白-家电下乡@161601300@160@1-00版@家电下乡产品@默认@2010-09-01"; + // 如果校验失败,下发报警 + if("N".Equals(result.Substring(0,1))) + { + sendPlcError(); + // 刷新页面提示信息 result.Substring(2) + return; + } //2.查询到的数据分割处理,结果中用"@"号分隔,刷新页面显示并存到scada数据库(表待建) string[] resultArray = result.Split('@'); // 输出结果 foreach (string item in resultArray) { - - MessageBox.Show(item); + Console.WriteLine(item); } //3.调条码系统保存接口入库SaveBarcodeInfo @@ -225,20 +237,141 @@ namespace Aucma.Core.ProductOffLine.ViewModels //5.分垛A,B库逻辑(先左边读到的条码分A库,右边读到的B库==>预留分库逻辑) //6.下发plc信号 - sendPlc(); + SendPlcPass(direction); } + #region plc交互 + + private SemaphoreSlim semaphore = new SemaphoreSlim(0); + /// + /// 下发plc放行信号 + /// + /// + private bool SendPlcPass(int direction) + { + bool result = false; + try + { + var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("成品下线Plc")); + if (obj != null) + { + if (obj.plc.IsConnected) + { + // 写入入库方向 + obj.plc.WriteInt32("D100", direction); + // 往plc写入放行信号 + obj.plc.WriteInt32("D102", 1); + // 等待plc反馈信号 + waitPlcSignal(); + semaphore.Wait(); + result = true; + } + else + { + log.Info("成品下线plc连接失败,请检查plc连接"); + } + } + else + { + log.Info("获取plc连接对象信息为空"); + } + } + catch (Exception ex) + { + log.Error("下发plc放行信号方法SendPlcPass()出现异常,ex:" + ex); + } + return result; + } /// - /// plc信号下发 + /// 读取plc放行反馈 /// - private void sendPlc() + /// + private void waitPlcSignal() { + try + { + lock (string.Empty) + { + bool isFlag = true; + var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("成品下线Plc")); + Task.Run(() => + { + if (obj != null) + { + if (obj.plc.IsConnected) + { + do + { + // 读取plc反馈信号 + if (obj.plc.ReadInt32("D102") == 2) + { + Console.WriteLine("收到plc放行成功"); + // 清空数据 + obj.plc.WriteInt32("D100", 0); + obj.plc.WriteInt32("D102", 0); + isFlag = false; + } + Thread.Sleep(1000); + } while (isFlag); + // 释放信号量 + semaphore.Release(); + } + else + { + log.Info("成品下线plc连接失败,请检查plc连接"); + } + } + else + { + log.Info("获取plc连接对象信息为空"); + } + }); + } + } + catch (Exception ex) + { + log.Error("读取plc放行反馈方法waitPlcSignal()出现异常,ex:" + ex); + } } - // 测试连接 + /// + /// 下发plc报警信号 + /// + private void sendPlcError() + { + try + { + var obj = PlcHelper.melsecList.FirstOrDefault(d => d.EquipName.Equals("成品下线Plc")); + if (obj != null) + { + if (obj.plc.IsConnected) + { + // 下发报警信号 + obj.plc.WriteInt32("D104", 1); + } + else + { + log.Info("成品下线plc连接失败,请检查plc连接"); + } + } + else + { + log.Info("获取plc连接对象信息为空"); + } + } + catch (Exception ex) + { + log.Error("下发plc放报警信号方法sendPlcError()出现异常,ex:" + ex); + } + } + #endregion + + /// + /// 连接测试 + /// void test() { string connectionString = "Data Source=(DESCRIPTION=(ADDRESS = (PROTOCOL = TCP)(HOST = 172.16.1.50)(PORT = 1521)))(CONNECT_DATA=(SERVICE_NAME=tmdata)));User ID=ILS_SORT;Password=Aucma_2019;"; @@ -266,5 +399,19 @@ namespace Aucma.Core.ProductOffLine.ViewModels } } } + + /// + /// 测试 + /// + private async void test2() + { + Task.Run(() => + { + Thread.Sleep(2000); + SendPlcPass(1); + Thread.Sleep(1000); + SendPlcPass(2); + }); + } } } diff --git a/Aucma.Core.ProductOffLine/ViewModels/StatisticsPageViewModel.cs b/Aucma.Core.ProductOffLine/ViewModels/StatisticsPageViewModel.cs index 5b3b62a4..8bc655d8 100644 --- a/Aucma.Core.ProductOffLine/ViewModels/StatisticsPageViewModel.cs +++ b/Aucma.Core.ProductOffLine/ViewModels/StatisticsPageViewModel.cs @@ -32,7 +32,6 @@ namespace Aucma.Core.ProductOffLine.ViewModels MaterialDataGrid.Add(new MaterialComplateInfo() { No = 10, ProductPlanCode = "8659452123", MaterialCode = "8659452123", MaterialName = "SC-AUCMA-农夫山泉,SC", PlanAmount = 50, CompleteAmount = 10}); } - #endregion #region 初始化datagrid diff --git a/Aucma.Core.ProductOffLine/appsettings.json b/Aucma.Core.ProductOffLine/appsettings.json index 113f7c8b..6e3873c4 100644 --- a/Aucma.Core.ProductOffLine/appsettings.json +++ b/Aucma.Core.ProductOffLine/appsettings.json @@ -194,10 +194,30 @@ "QuartzNetJob": { "Enabled": true }, - "Scanner": {//扫码器 + "Scanner": { //扫码器 "Enabled": true + }, + "Scanner1": { //扫码器1 + "Ip": "192.168.1.19", + "Name": "扫码器1" + }, + "Scanner2": { //扫码器2 + "Ip": "192.168.1.20", + "Name": "扫码器2" + }, + "ScannerGun": { //扫码枪 + "Enabled": false } }, + "PLCServer": [ + { + "Id": 1, + "EquipName": "成品下线Plc", + "IP": "127.0.0.1", + "Port": 6000 + } + + ], "IpRateLimiting": { "EnableEndpointRateLimiting": false, //False: globally executed, true: executed for each "StackBlockedRequests": false, //False: Number of rejections should be recorded on another counter @@ -245,4 +265,5 @@ } ] } + }