Explorar el Código

新增RGV相关,并修改出库规则

林豪 左 hace 3 años
padre
commit
6ef885759a

+ 5 - 1
DBHelper/DBHelper.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <TargetFramework>net5.0</TargetFramework>
@@ -13,4 +13,8 @@
     <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.5" />
   </ItemGroup>
 
+  <ItemGroup>
+    <ProjectReference Include="..\Logs\Logs.csproj" />
+  </ItemGroup>
+
 </Project>

+ 53 - 0
DBHelper/DbLog.cs

@@ -0,0 +1,53 @@
+using Logs;
+using System.Collections.Generic;
+
+namespace DBHelper
+{
+    public class DbLog : ILogType
+    {
+        /// <summary>
+        /// 日志名称
+        /// </summary>
+        public string LogName => "DB";
+
+        /// <summary>
+        /// 日志
+        /// </summary>
+        public static ILogType Log { get; set; }
+
+        public Dictionary<string, string> SubLogNames { get; set; }
+
+        static DbLog()
+        {
+            if (Log == null)
+                Log = new DbLog();
+        }
+
+        public DbLog()
+        {
+            SubLogNames = new Dictionary<string, string>
+            {
+                {"DB", "Db" }
+            };
+            LogHelper.Init(this);
+        }
+
+        /// <summary>
+        /// 用于记录DB执行内容
+        /// </summary>
+        /// <param name="msg"></param>
+        public static void DBEX(string msg)
+        {
+            Log.Info(msg, "DBEX");
+        }
+
+        /// <summary>
+        /// 用于记录DB清理记录
+        /// </summary>
+        /// <param name="msg"></param>
+        public static void DB_CLEAN(string msg)
+        {
+            Log.Info(msg, "DB_CLEAN");
+        }
+    }
+}

+ 12 - 10
DBHelper/EFLoggerProvider.cs

@@ -1,16 +1,14 @@
 using Microsoft.Extensions.Logging;
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
 namespace DBHelper
 {
     public class EFLoggerProvider : ILoggerProvider
     {
         public ILogger CreateLogger(string categoryName) => new EFLogger(categoryName);
-        public void Dispose() { }
+
+        public void Dispose()
+        { }
     }
 
     public class EFLogger : ILogger
@@ -28,13 +26,17 @@ namespace DBHelper
                     && logLevel == LogLevel.Information)
             {
                 var logContent = formatter(state, exception);
+
+                if (logContent.Contains("SRM5") || logContent.Contains("STATION5") || logContent.Contains("RGV5") || logContent.Contains("BCR8")) return;
+                DbLog.DBEX(logContent);
                 //TODO: 拿到日志内容想怎么玩就怎么玩吧
-                Console.WriteLine();
-                Console.ForegroundColor = ConsoleColor.Green;
-                Console.WriteLine(logContent);
-                Console.ResetColor();
+                //Console.WriteLine();
+                //Console.ForegroundColor = ConsoleColor.Green;
+                //Console.WriteLine(logContent);
+                //Console.ResetColor();
             }
         }
+
         public IDisposable BeginScope<TState>(TState state) => null;
     }
-}
+}

BIN
DLL/PLC.Siemens.dll


+ 191 - 62
Projects/永冠OPP/WCS.Service/Extensions/DeviceExtension.cs

@@ -4,6 +4,7 @@ using System.Linq;
 using WCS.Core;
 using WCS.Entity;
 using WCS.Entity.Protocol;
+using WCS.Entity.Protocol.RGV;
 using WCS.Service.Helpers;
 
 namespace WCS.Service.Extensions
@@ -13,10 +14,32 @@ namespace WCS.Service.Extensions
     /// </summary>
     public class StationDeviceGroup : DeviceGroup<IStation520, IStation521, IStation523>
     {
+        public StationDeviceGroup(WCS_DEVICE entity) : base(entity)
+        {
+        }
+
         private List<RGVDevice> RGVs;
 
-        public StationDeviceGroup(WCS_DEVICE entity) : base(entity)
+        /// <summary>
+        /// 设备组自身的位置
+        /// </summary>
+        public float Position
         {
+            get
+            {
+                return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Location;
+            }
+        }
+
+        /// <summary>
+        /// 设备组所在环穿的总长度
+        /// </summary>
+        public float Length
+        {
+            get
+            {
+                return StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE).Length;
+            }
         }
 
         /// <summary>
@@ -62,35 +85,55 @@ namespace WCS.Service.Extensions
         public List<Device<IStation520, IStation521, IStation523>> TaskedDeviceGetNextAddress()
         {
             var a = Items.Where(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum > 10000)
-                        .Where(v => v.Data2.Goodsend.ToString() == v.Entity.CODE && v.Data2.Goodsend != 0)
+                        .Where(v => v.Data2.Goodsend != 0)
                         .ToList();
             return a.Count == 0 ? null : a;
         }
 
-        public float Position { get; }
-        public float Length { get; }
-
+        /// <summary>
+        ///
+        /// </summary>
+        /// <returns></returns>
         public RGVDevice NextRGV()
         {
             return new RGVDevice(new WCS_DEVICE());
         }
 
+        /// <summary>
+        /// 计算目标RGV与站台自身的距离
+        /// </summary>
+        /// <param name="rgv"></param>
+        /// <returns></returns>
         public float Distance(RGVDevice rgv)
         {
             return Math.Abs((Position - rgv.Position + Length) % Length);
         }
 
+        /// <summary>
+        /// 当前RGV
+        /// </summary>
+        /// <returns></returns>
         public RGVDevice CurrentRGV()
         {
             return new RGVDevice(new WCS_DEVICE());
         }
 
         /// <summary>
-        ///
+        /// 是否需要RGV
         /// </summary>
-        /// <returns></returns>
+        /// <returns>true:需要RGV false:不需要RGV</returns>
         public bool NeedRgv()
         {
+            var rgvs = Device.Where(v => v.IsRGV()).Select(v => v.Device<IRGV521>());
+            var code = Entity.CODE.Replace("G", "").ToShort();
+            if (rgvs.Any(v => v.Data.DestPosition_1 == code && v.Data.SystemStatus != RGVRunStatus.空闲))
+                throw new Exception(LogHelper.SpliceLogMessage("已有RGV执行中", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+            foreach (var item in Items)
+            {
+                if (item.Data3.Status.HasFlag(StationStatus.运行状态位)) return false;
+                if (!item.Data2.Status.HasFlag(IstationStatus.光电状态)) return false;
+            }
+
             return true;
         }
     }
@@ -116,35 +159,35 @@ namespace WCS.Service.Extensions
             if (Data3.Status.HasFlag(StationStatus.运行状态位)) return true;
             //上一次的任务还未执行
             if (Data.VoucherNo != Data2.VoucherNo)
-                throw new Exception(LogHelper.SpliceLogMessage($"等待任务[{Data2.Tasknum}]执行", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                throw new Exception(LogHelper.SpliceLogMessage($"等待任务[{Data2.Tasknum}]执行", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
             //没有光电
             if (!Data2.Status.HasFlag(IstationStatus.光电状态)) return true;
+            //没有请求
+            if (type != IstationRequest.无 && Data2.Request != type)
+                throw new Exception(LogHelper.SpliceLogMessage($"有光电有任务无 {type}", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
             //没有任务号
             switch (type)
             {
                 case IstationRequest.无:
-                    if (Data2.Tasknum > 10000)
-                        throw new Exception(LogHelper.SpliceLogMessage($"设备已有任务任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                    if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
+                        throw new Exception(LogHelper.SpliceLogMessage($"设备已有任务任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                     break;
 
                 case IstationRequest.扫码入库:
-                    if (Data2.Tasknum > 10000)
-                        throw new Exception(LogHelper.SpliceLogMessage($"设备已有任务任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                    if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
+                        throw new Exception(LogHelper.SpliceLogMessage($"设备已有任务任务", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                     break;
 
                 case IstationRequest.堆垛机放货完成请求目标地址:
-                    if (Data2.Tasknum < 10000)
-                        throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                    if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
+                        throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                     break;
 
                 case IstationRequest.请求分配目标地址:
-                    if (Data2.Tasknum < 10000)
-                        throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                    if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)
+                        throw new Exception(LogHelper.SpliceLogMessage($"设备无任务信息", Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                     break;
             }
-            //没有请求
-            if (type != IstationRequest.无 && Data2.Request != type)
-                throw new Exception(LogHelper.SpliceLogMessage($"有光电有任务无 {type}", Entity.CODE, WCS_EXCEPTIONTYPE.设备异常));
 
             return false;
         }
@@ -155,49 +198,62 @@ namespace WCS.Service.Extensions
     /// </summary>
     public class RGVDevice : Device<IRGV520, IRGV521, IRGV523>
     {
-        //需要记录每一个站台的位置
+        static RGVDevice()
+        {
+            AllRGVList = Device.Where(v => v.IsRGV() && v.CODE != "RGV8").Select(v => v.Create<RGVDevice>()).ToList();
+        }
 
-        /// <summary>
-        /// 涂布环穿 位置配置
+        public RGVDevice(WCS_DEVICE entity) : base(entity)
+        {
+        }
+
+        /// 所有环穿RGV
         /// </summary>
-        private static List<RGVStationLocation> Coating = new List<RGVStationLocation>();
+        private static List<RGVDevice> AllRGVList { get; set; }
 
         /// <summary>
-        /// 拉膜环穿 位置配置
+        /// 与当前RGV处于同一环穿的RGV
         /// </summary>
-        private static List<RGVStationLocation> PullFilm = new List<RGVStationLocation>();
-
-        public float Position
+        public List<RGVDevice> RGVList
         {
             get
             {
-                return Data2.Position;
+                return AllRGVList.Where(v => v.Entity.PROTOCOLS.Any(d => Entity.PROTOCOLS.Any(e => e.DB.ID == d.DB.ID)))
+                    .Where(v => v.Entity.CODE != Entity.CODE).ToList();
             }
         }
 
-        private static List<RGVDevice> AllRGVList
-        {
-            get; set;
-        }
-
-        static RGVDevice()
+        /// <summary>
+        /// RGV当前位置
+        /// </summary>
+        public float Position
         {
-            AllRGVList = Device.Where(v => v.IsRGV() && v.CODE != "RGV8").Select(v => v.Create<RGVDevice>()).ToList();
+            get
+            {
+                return Data2.Position;
+            }
         }
 
-        public float Length { get; }
-
-        public List<RGVDevice> RGVList
+        /// <summary>
+        /// 与当前RGV处于同一环穿的RGV
+        /// </summary>
+        public List<StationLocation> LocationList
         {
             get
             {
-                return AllRGVList.Where(v => v.Entity.PROTOCOLS.Any(d => Entity.PROTOCOLS.Any(e => e.DB.ID == d.DB.ID)))
-                    .Where(v => v.Entity.CODE != Entity.CODE).ToList();
+                return StationLocation.ALLlocations.Where(v => Entity.PROTOCOLS.Any(p => p.DB.PLC.CODE == v.PLC)).ToList();
             }
         }
 
-        public RGVDevice(WCS_DEVICE entity) : base(entity)
+        /// <summary>
+        /// 总长度
+        /// </summary>
+        public float Length
         {
+            get
+            {
+                return LocationList.FirstOrDefault().Length;
+            }
         }
 
         /// <summary>
@@ -206,7 +262,8 @@ namespace WCS.Service.Extensions
         /// <returns></returns>
         public RGVDevice Before()
         {
-            var arr = AllRGVList.OrderBy(v => v.Position);
+            //按照位置排序
+            var arr = RGVList.OrderBy(v => v.Position);
             var rgv = arr.FirstOrDefault(v => v.Position > Position);
             if (rgv == null)
                 rgv = arr.LastOrDefault(v => v.Position < Position);
@@ -219,11 +276,15 @@ namespace WCS.Service.Extensions
         /// <returns></returns>
         public RGVDevice After()
         {
-            return new RGVDevice(new WCS_DEVICE());
+            var arr = RGVList.OrderBy(v => v.Position);
+            var rgv = arr.FirstOrDefault(v => v.Position < Position);
+            if (rgv == null)
+                rgv = arr.LastOrDefault(v => v.Position > Position);
+            return rgv;
         }
 
         /// <summary>
-        /// 两个RGV之间的距离
+        /// 计算当前RGV与指定RGV之间的距离
         /// </summary>
         /// <param name="after"></param>
         /// <returns></returns>
@@ -242,40 +303,67 @@ namespace WCS.Service.Extensions
         }
 
         /// <summary>
-        /// 移动
+        /// 写入移动任务
         /// </summary>
-        /// <param name="addr"></param>
+        /// <param name="addr">目标地址</param>
         public void Move(StationDeviceGroup addr)
         {
         }
 
         /// <summary>
-        /// 选择出库
+        /// 写入取货任务
         /// </summary>
-        /// <param name="addr"></param>
+        /// <param name="addr">目标地址</param>
         public void Pick(StationDeviceGroup addr)
         {
         }
 
-        public void Put()
+        /// <summary>
+        /// 写入放货任务
+        /// </summary>
+        /// <param name="addr">目标地址</param>
+        public void Put(StationDeviceGroup addr)
         {
         }
 
+        /// <summary>
+        /// 筛选出所有与当前RGV距离小于指定长度的RGV
+        /// </summary>
+        /// <param name="distance">指定长度</param>
+        /// <returns></returns>
         public RGVDevice[] RgvAfter(float distance)
         {
-            return AllRGVList.Where(v => Distance(v) < distance).ToArray();
+            return RGVList.Where(v => Distance(v) < distance).ToArray();
         }
 
+        /// <summary>
+        /// 当前RGV是否有拦住传入RGV
+        /// </summary>
+        /// <param name="rgv">RGV</param>
+        /// <returns></returns>
         public bool StopedByMe(RGVDevice rgv)
         {
+            //目标站台
             var target = rgv.Data2.DestPosition_1;
+            //获取目标站台的设备组信息
             var station = Device.Find($"G{target}").Create<StationDeviceGroup>();
+            //当前RGV与目标站台的距离小于传入RGV到达目标站台的距离
             return station.Distance(this) < station.Distance(rgv);
         }
 
+        /// <summary>
+        /// 获取当前RGV的下一个站台,即距离最近的一个站台
+        /// </summary>
+        /// <returns></returns>
         public StationDeviceGroup NextStation()
         {
-            return new StationDeviceGroup(new WCS_DEVICE());
+            //先取当前RGV与所有站台的距离
+            var dev = LocationList.OrderBy(v =>
+            {
+                var dev = Device.Find(v.Station).Create<StationDeviceGroup>();
+                return dev.Distance(this);
+            }).FirstOrDefault();
+            return Device.Find(dev.Station).Create<StationDeviceGroup>(); ;
         }
     }
 
@@ -296,18 +384,49 @@ namespace WCS.Service.Extensions
             return Entity.ROUTES.Select(v => v.NEXT) //巷道
                                 .SelectMany(v => v.ROUTES.Select(d => d.NEXT)) //放货点
                                 .Where(v => v.IsConv()) //必须是输送线
-                                .Select(v => new StationDevice(v)).ToList();
+                                .Select(v => v.Create<StationDevice>()).ToList();
         }
     }
 
-    public class RGVStationLocation
+    /// <summary>
+    /// 站台位置信息
+    /// </summary>
+    public class StationLocation
     {
-        public RGVStationLocation(string station, string stationLocation, string startingPoint, string endPoint)
+        /// <summary>
+        /// 所有环穿站台的信息
+        /// </summary>
+        public static List<StationLocation> ALLlocations { get; set; }
+
+        static StationLocation()
+        {
+            ALLlocations.AddRange(new List<StationLocation>() {
+                new StationLocation("G1187",0,"RGV1",0),
+                new StationLocation("G1196",0,"RGV1",0),
+                new StationLocation("G1205",0,"RGV1",0),
+                new StationLocation("G1214",0,"RGV1",0),
+                new StationLocation("G1222",0,"RGV1",0),
+                new StationLocation("G1164",0,"RGV1",0),
+                new StationLocation("G1285",0,"RGV3",0),
+                new StationLocation("G1401",0,"RGV3",0),
+                new StationLocation("G1294",0,"RGV3",0),
+                new StationLocation("G1410",0,"RGV3",0),
+                new StationLocation("G1303",0,"RGV3",0),
+                new StationLocation("G1417",0,"RGV3",0),
+                new StationLocation("G1412",0,"RGV3",0),
+                new StationLocation("G1426",0,"RGV3",0),
+                new StationLocation("G1332",0,"RGV3",0),
+                new StationLocation("G1391",0,"RGV3",0),
+                new StationLocation("G1399",0,"RGV3",0),
+            });
+        }
+
+        public StationLocation(string station, int location, string plc, int length)
         {
             Station = station;
-            StationLocation = stationLocation;
-            StartingPoint = startingPoint;
-            EndPoint = endPoint;
+            Location = location;
+            PLC = plc;
+            Length = length;
         }
 
         /// <summary>
@@ -318,16 +437,26 @@ namespace WCS.Service.Extensions
         /// <summary>
         /// 输送机在环轨中的位置
         /// </summary>
-        public string StationLocation { get; set; }
+        public int Location { get; set; }
 
         /// <summary>
-        /// RGV起始
+        /// 所属PLC名称
         /// </summary>
-        public string StartingPoint { get; set; }
+        public string PLC { get; set; }
 
         /// <summary>
-        /// RGV结束
+        /// 所属环穿轨道的长度
         /// </summary>
-        public string EndPoint { get; set; }
+        public int Length { get; set; }
+    }
+
+    /// <summary>
+    /// 巷道信息
+    /// </summary>
+    public class TunnelInfo
+    {
+        public WCS_DEVICE Tunnel;
+        public WCS_DEVICE taskIN;
+        public Device<ISRM520, ISRM521, ISRM537> SRM;
     }
 }

+ 43 - 4
Projects/永冠OPP/WCS.Service/Extensions/TaskExtension.cs

@@ -1,8 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using WCS.Entity;
 
 namespace WCS.Service.Extensions
 {
@@ -11,6 +10,46 @@ namespace WCS.Service.Extensions
     /// </summary>
     public static class TaskExtension
     {
-        //public static bool Get
+        public static T Create<T>(WCS_TASK source)
+        {
+            return (T)Activator.CreateInstance(typeof(T), source);
+        }
+
+        /// <summary>
+        /// 获取可用的出库任务
+        /// </summary>
+        /// <param name="tasks"></param>
+        /// <returns></returns>
+        public static List<WCS_TASK> GetOutTask(this List<WCS_TASK> tasks)
+        {
+            var taskids = tasks.Select(v => Create<Task>(v)).OrderBy(v => v.Line).ThenBy(v => v.Col).ThenBy(v => v.Layer).Take(2).DistinctBy(v => v.SRMSTATION).Select(v => v.ID);
+            return tasks.Where(v => taskids.Contains(v.ID)).ToList();
+        }
+    }
+
+    public class Task : WCS_TASK
+    {
+        /// <summary>
+        /// 行
+        /// </summary>
+        public short Line { get; set; }
+
+        /// <summary>
+        /// 列
+        /// </summary>
+        public short Col { get; set; }
+
+        /// <summary>
+        /// 层
+        /// </summary>
+        public short Layer { get; set; }
+
+        public Task()
+        {
+            var addrFrom = ADDRFROM.Split("-");
+            Line = addrFrom[0].ToShort();
+            Col = addrFrom[1].ToShort();
+            Layer = addrFrom[2].ToShort();
+        }
     }
-}
+}

+ 2 - 2
Projects/永冠OPP/WCS.Service/Extensions/TypeExtension.cs

@@ -31,8 +31,8 @@ namespace WCS.Service.Extensions
         /// <returns> true:是奇数   false:是偶数</returns>
         public static bool OddNumberOrEven(this short value)
         {
-            if (value % 2 == 0) return true;
-            else return false;
+            if (value % 2 == 0) return false;
+            else return true;
         }
     }
 }

+ 1 - 1
Projects/永冠OPP/WCS.Service/Extensions/WCS_TaskExtensions.cs

@@ -21,7 +21,7 @@ namespace WCS.Service.Extensions
                 {
                     WCS_TASKID = task.ID,
                     NewStatus = task.STATUS,
-                    UPDATETIME = task.UPDATETIME,
+                    UPDATETIME = DateTime.Now,
                     upStatus = task.UPLOADED,
                     Node = cl.FullName,
                     UPDATEUSER = "WCS",

+ 5 - 9
Projects/永冠OPP/WCS.Service/Handlers/DataClearHandler.cs

@@ -1,26 +1,21 @@
 using DBHelper;
 using Microsoft.EntityFrameworkCore;
 using System;
-using System.Collections.Generic;
 using System.ComponentModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using WCS.Core;
 using WCS.Entity;
-using WCS.Entity.Protocol; 
 
 namespace WCS.Service
 {
     [Description("数据清理")]
-    class DataClearHandler : LogicHandler
+    internal class DataClearHandler : LogicHandler
     {
         public override void Start()
         {
-            
         }
 
-        DateTime last = DateTime.MinValue;
+        private DateTime last = DateTime.MinValue;
+
         public override void Update(double milliseconds)
         {
             if ((DateTime.Now - last).TotalMilliseconds < 1000 * 60 * 60 * 24)
@@ -40,8 +35,9 @@ namespace WCS.Service
                         continue;
                     var sSql = $"Delete {tType.Name} where datediff(dd,Frame,getdate())>7";
                     db.Default.Database.ExecuteSqlRaw(sSql);
+                    DBHelper.DbLog.DB_CLEAN(sSql);
                 }
             });
         }
     }
-}
+}

+ 3 - 1
Projects/永冠OPP/WCS.Service/Helpers/LogHelper.cs

@@ -3,6 +3,7 @@ using Microsoft.EntityFrameworkCore;
 using System;
 using System.Linq;
 using WCS.Entity;
+using WCS.Service.Log;
 
 namespace WCS.Service.Helpers
 {
@@ -82,8 +83,9 @@ namespace WCS.Service.Helpers
         /// <param name="device">异常关联设备</param>
         /// <param name="type">异常类型</param>
         /// <returns></returns>
-        public static string SpliceLogMessage(string msg, string device, WCS_EXCEPTIONTYPE type)
+        public static string SpliceLogMessage(string msg, string device, WCS_EXCEPTIONTYPE type,Type type1)
         {
+            InfoLog.INFO_ERROR($"{type1.FullName}--{msg}--{device}--{type}");
             return $"{msg}|{device}|{type}";
         }
     }

+ 2 - 0
Projects/永冠OPP/WCS.Service/Program.cs

@@ -5,6 +5,7 @@ using System;
 using System.Runtime.InteropServices;
 using System.Threading;
 using System.Threading.Tasks;
+using WCS.Service.Log;
 
 namespace WCS.Service
 {
@@ -22,6 +23,7 @@ namespace WCS.Service
                 else
                 {
                     Console.WriteLine("请勿重复运行");
+                    InfoLog.INFO_INIT("请勿重复运行");
                     Task.Delay(2000).Wait();
                 }
             }

+ 1 - 1
Projects/永冠OPP/WCS.Service/ProtocolProxy.cs

@@ -100,7 +100,7 @@ namespace WCS.Service
         {
             MessagePackSerializer.DefaultOptions = StandardResolver.Options.WithCompression(MessagePackCompression.Lz4Block);
             //Redis = new RedisClient("192.168.249.120,password=123456,database=11");
-            Redis = new RedisClient("81.69.99.176,database=10");
+            Redis = new RedisClient("212.64.66.35,database=10");
             Redis.Serialize = obj =>
             {
                 var bytes = MessagePackSerializer.Serialize(obj);

+ 3 - 1
Projects/永冠OPP/WCS.Service/Uploader.cs

@@ -2,7 +2,7 @@
 using System;
 using System.Linq;
 using WCS.Entity;
-using WCS.Service.Extensions;
+using WCS.Service.Log;
 
 namespace WCS.Service
 {
@@ -40,8 +40,10 @@ namespace WCS.Service
                         try
                         {
                             WMS.UpdateTask(task.ADDRNEXT.ToString(), task.WMSTASK, (int)task.STATUS);
+                            var st = task.UPLOADED;
                             task.UPLOADED = task.STATUS;
                             //task.CreateStatusLog(db);
+                            InfoLog.INFO_SYTASKSTATUS($"[{task.ID}]---old:[{st}]-new:[{task.UPLOADED}]");
                         }
                         catch (Exception ex)
                         {

+ 0 - 4
Projects/永冠OPP/WCS.Service/WCS.Service.csproj

@@ -47,8 +47,4 @@
       <HintPath>DLL\PLCConnecter.dll</HintPath>
     </Reference>
   </ItemGroup>
-
-  <ItemGroup>
-    <Folder Include="Logs\" />
-  </ItemGroup>
 </Project>

+ 4 - 1
Projects/永冠OPP/WCS.Service/WCSDB.cs

@@ -1,6 +1,7 @@
 using DBHelper;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.Linq;
@@ -29,7 +30,9 @@ namespace WCS.Service
 
         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
         {
-            optionsBuilder.UseSqlServer(AppSettings.Config.GetConnectionString("WCSDB"));
+            var loggerFactory = new LoggerFactory();
+            loggerFactory.AddProvider(new EFLoggerProvider());
+            optionsBuilder.UseSqlServer(AppSettings.Config.GetConnectionString("WCSDB")).UseLoggerFactory(loggerFactory).EnableSensitiveDataLogging();
             //optionsBuilder.UseLoggerFactory(LoggerFactory.Create(builder =>
             //{
             //    builder.AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information).AddConsole();

+ 9 - 8
Projects/永冠OPP/WCS.Service/WebApi/WCSApi.cs

@@ -32,7 +32,7 @@ namespace WCS.Service.WebApi
                                 throw new Exception("任务号" + wmstaskid + "重复下发");
 
                             var scid = int.Parse(obj.SRMNo.Last().ToString());
-                            var tunnel = (scid > 3 ? "TM" : "TY") + obj.StartTunnel;
+                            var tunnel = "TY" + obj.StartTunnel;
                             var task = new WCS_TASK
                             {
                                 TYPE = TaskType.移库,
@@ -63,7 +63,7 @@ namespace WCS.Service.WebApi
                             {
                                 TYPE = TaskType.出库,
                                 STATUS = WCS.Entity.TaskStatus.新建,
-                                DEVICE = "SC" + obj.SRMNo.Last(),
+                                DEVICE = "SRM" + obj.SRMNo.Last(),
                                 BARCODE = obj.PalletCode,
                                 ADDRFROM = string.Format("{0}-{1}-{2}", obj.StartRow, obj.StartCol, obj.StartLayer),
                                 ADDRTO = obj.EndLocation,
@@ -73,6 +73,7 @@ namespace WCS.Service.WebApi
                                 WMSTASK = int.Parse(obj.WMSTaskNo),
                                 ADDRNEXT = obj.EndLocation
                             };
+
                             //当前货物可以使用的放货点
                             var deliveryPoints = Device.Find(task.DEVICE).Create<SRMDevice>().GetDeliveryPoint();
                             //确定放货站台 通过设备组关联 此时一定是一组设备组
@@ -81,23 +82,23 @@ namespace WCS.Service.WebApi
                             //结果为当前堆垛机可用设备 此时会是两个单独的设备
                             deliveryPoints = deliveryPoints.Where(v => group.Contains(v.Entity)).OrderByDescending(v => v.Entity.CODE).ToList();
 
+                            var addrTo = Device.Find(task.ADDRTO).Create<StationDeviceGroup>().Items.ToArray();
+
                             //判断是否可以到达
                             //确定当前工位的货物是一工位还是二工位
                             if (obj.StartCol.ToShort().OddNumberOrEven())
                             {
                                 //一工位 也是设备在堆垛机放货后的第一个地点
                                 task.SRMSTATION = deliveryPoints[0].Entity.CODE;
-                                var g = Device.Find(task.ADDRTO).Create<StationDeviceGroup>().Items.ToArray();
-                                if (deliveryPoints[0].Entity.PATHS.Any(v => v.END == g[0].Entity)) task.ADDRTO = g[0].Entity.CODE;
-                                else task.ADDRTO = g[1].Entity.CODE;
+                                if (deliveryPoints[0].Entity.PATHS.Any(v => v.END == addrTo[0].Entity)) task.ADDRTO = addrTo[0].Entity.CODE;
+                                else task.ADDRNEXT = addrTo[0].Entity.CODE;
                             }
                             else
                             {
                                 //二工位
                                 task.SRMSTATION = deliveryPoints[1].Entity.CODE;
-                                var g = Device.Find(task.ADDRTO).Create<StationDeviceGroup>().Items.ToArray();
-                                if (deliveryPoints[1].Entity.PATHS.Any(v => v.END == g[0].Entity)) task.ADDRTO = g[0].Entity.CODE;
-                                else task.ADDRTO = g[1].Entity.CODE;
+                                if (deliveryPoints[1].Entity.PATHS.Any(v => v.END == addrTo[0].Entity)) task.ADDRTO = addrTo[0].Entity.CODE;
+                                else task.ADDRNEXT = addrTo[1].Entity.CODE;
                             }
 
                             db.Default.Add(task);

+ 12 - 2
Projects/永冠OPP/WCS.Service/Worker.cs

@@ -1,8 +1,11 @@
 using DBHelper;
+using Logs;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
 using System;
+using System.IO;
 using System.Linq;
 using System.Reflection;
 using System.Text;
@@ -10,7 +13,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using WCS.Core;
 using WCS.Entity;
-using WCS.Service.Helpers;
+using WCS.Service.Log;
 
 namespace WCS.Service
 {
@@ -27,7 +30,10 @@ namespace WCS.Service
         {
             if (stoppingToken.IsCancellationRequested)
                 return;
+            var logconfig = JsonConvert.DeserializeObject<LogConfig>(File.ReadAllText("config.json", Encoding.Default));
+            Logs.LogHelper.SetConfigInfo(logconfig);
             _logger.LogInformation("WCS开始启动");
+            InfoLog.INFO_INIT("WCS开始启动");
             Configs.DebugRedisUrl = "127.0.0.1";
             Configs.ProtocolProxyBaseType = typeof(ProtocolProxy);
             Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
@@ -52,7 +58,7 @@ namespace WCS.Service
                 WMS.TaskException(d, s);
             };
 
-            LogicHandler.DbLog = (msg, device, type) => LogHelper.AddWCS_EXCEPTION(msg, device, type);
+            LogicHandler.DbLog = (msg, device, type) => Helpers.LogHelper.AddWCS_EXCEPTION(msg, device, type);
 
             //Configs.DoCmds = act =>
             //{
@@ -96,6 +102,7 @@ namespace WCS.Service
                 Device.AddFlag(DF.月台区, "G1469", "G1561", "G1538", "G1574", "G1509");
                 Device.AddFlag(DF.RGV1, "G1244");
                 Device.AddFlag(DF.RGV2, "G1244");
+                Device.AddFlag(DF.SRM放货, "1473", "1476","1493","1494");
 
                 #endregion 设备扩展数据配置
 
@@ -109,10 +116,12 @@ namespace WCS.Service
                 LogicHandler.StartAll();
                 //Uploader.Start();
                 _logger.LogInformation("WCS启动成功");
+                InfoLog.INFO_INIT("WCS启动成功");
             }
             catch (Exception ex)
             {
                 _logger.LogError("WCS启动失败{0}", ex.Message);
+                InfoLog.INFO_INIT($"WCS启动失败{ex.Message}");
             }
         }
 
@@ -121,6 +130,7 @@ namespace WCS.Service
         public override Task StopAsync(CancellationToken cancellationToken)
         {
             _logger.LogError("WCS关闭");
+            InfoLog.INFO_INIT("WCS关闭");
             LogicHandler.StopAll();
             //Uploader.Stop();
             return base.StopAsync(cancellationToken);

+ 19 - 5
Projects/永冠OPP/WCS.Service/Works/RGV/RGVWorks.cs

@@ -26,20 +26,34 @@ namespace WCS.Service.Works.RGV
             if (obj.WhetherToExecute()) return;
 
             //筛选出有任务号和起始及目标地址的设备
-            var dev = obj.RGVGetTaskedDevice() ?? throw new Exception(LogHelper.SpliceLogMessage("无可用任务", rgv.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+            var dev = obj.RGVGetTaskedDevice() ?? throw new Exception(LogHelper.SpliceLogMessage("无可用任务", rgv.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
 
             DB.Do(db =>
             {
                 var taskids = dev.Select(v => v.Data2.Tasknum);
                 var tasks = db.Default.Set<WCS_TASK>().Where(p => taskids.Contains(p.ID));
-                if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1) throw new Exception(LogHelper.SpliceLogMessage("任务组ID不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
-                if (tasks.GroupBy(p => p.TaskGroupKey).Count() == 0) throw new Exception(LogHelper.SpliceLogMessage("无任务组ID", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                if (tasks.GroupBy(p => p.TaskGroupKey).Count() > 1)
+                    throw new Exception(LogHelper.SpliceLogMessage("任务组ID不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                if (tasks.GroupBy(p => p.TaskGroupKey).Count() == 0)
+                    throw new Exception(LogHelper.SpliceLogMessage("无任务组ID", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                 var gw1 = obj.Items.ToArray()[0];
                 var gw2 = obj.Items.ToArray()[1];
+                if (gw1.Data2.Tasknum != 0 && gw2.Data2.Tasknum != 0)
+                {
+                    if (gw1.Data2.Goodsend != gw2.Data2.Goodsend) throw new Exception(LogHelper.SpliceLogMessage($"{obj.Entity.Code}目标地址不一致", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                }
                 rgv.Data.TaskID_1 = gw1.Data2.Tasknum;
                 rgv.Data.TaskID_2 = gw2.Data2.Tasknum;
-                rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
-                rgv.Data.DestPosition_1 = gw1.Data2.Goodsend;
+                if (gw1.Data2.Tasknum != 0)
+                {
+                    rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
+                    rgv.Data.DestPosition_1 = gw1.Data2.Goodsend;
+                }
+                else
+                {
+                    rgv.Data.StartPosition_1 = gw1.Entity.CODE.ToShort();
+                    rgv.Data.DestPosition_1 = gw2.Data2.Goodsend;
+                }
                 rgv.Data.Trigger_1++;
 
                 foreach (var task in tasks)

+ 64 - 42
Projects/永冠OPP/WCS.Service/Works/SRM/SRMWork.cs

@@ -10,6 +10,7 @@ using WCS.Entity.Protocol.SRM;
 using WCS.Service.Extensions;
 using WCS.Service.Handlers;
 using WCS.Service.Helpers;
+using WCS.Service.Log;
 
 namespace WCS.Service.Works.SRM
 {
@@ -34,10 +35,13 @@ namespace WCS.Service.Works.SRM
             if (obj.Data3.SCAlarm != 0)
             {
                 if (obj.Entity.WakeupOn(5000)) WMS.DevInfo(obj.Entity.CODE, obj.Data3.SCAlarm.ToString());
+                InfoLog.INFO_SRMALARM($"{obj.Entity.CODE}-{obj.Data3.SCAlarm}");
                 return;
             }
-            if (obj.Data.FinishedACK_1 == 1 || obj.Data.FinishedACK_2 == 1) throw new Exception(LogHelper.SpliceLogMessage($"堆垛机完成任务WCS反馈信号未清除", deviceCode, WCS_EXCEPTIONTYPE.设备异常));
-            if (obj.Data2.VoucherNo_1 != obj.Data.VoucherNo_1) throw new Exception(LogHelper.SpliceLogMessage($"等待执行{obj.Data.TaskID_1}-{obj.Data.TaskID_2}", deviceCode, WCS_EXCEPTIONTYPE.设备异常));
+            if (obj.Data.FinishedACK_1 == 1 || obj.Data.FinishedACK_2 == 1)
+                throw new Exception(LogHelper.SpliceLogMessage($"堆垛机完成任务WCS反馈信号未清除", deviceCode, WCS_EXCEPTIONTYPE.设备异常, GetType()));
+            if (obj.Data2.VoucherNo_1 != obj.Data.VoucherNo_1 || obj.Data2.VoucherNo_2 != obj.Data.VoucherNo_2)
+                throw new Exception(LogHelper.SpliceLogMessage($"等待执行{obj.Data.TaskID_1}-{obj.Data.TaskID_2}", deviceCode, WCS_EXCEPTIONTYPE.设备异常, GetType()));
 
             //处理堆垛机已完成的任务
             if (obj.Data2.FinishedTask_1 != 0 || obj.Data2.FinishedTask_2 != 0)
@@ -53,9 +57,9 @@ namespace WCS.Service.Works.SRM
                         if (taskIds[i] == 0) continue;
                         //获取当前工位的目标地址
                         var ELine = i == 0 ? obj.Data.ELine_1.ToString() : obj.Data.ELine_2.ToString();
-                        task = db.Default.Set<WCS_TASK>().Find(taskIds[i]);
-                        if (task.STATUS < TaskStatus.堆垛机执行)
-                            throw new Exception(LogHelper.SpliceLogMessage($"堆垛机已完成任务[{task.ID}]但WCS状态为[{task.STATUS}],应为[{TaskStatus.堆垛机执行}]", deviceCode, WCS_EXCEPTIONTYPE.逻辑异常));
+                        task = db.Default.Set<WCS_TASK>().Single(v => taskIds[i] == v.ID);
+                        if (task.STATUS != TaskStatus.堆垛机执行)
+                            throw new Exception(LogHelper.SpliceLogMessage($"堆垛机已完成任务[{task.ID}]但WCS状态为[{task.STATUS}],应为[{TaskStatus.堆垛机执行}]", deviceCode, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
 
                         if (task.TYPE == TaskType.入库)
                         {
@@ -105,7 +109,7 @@ namespace WCS.Service.Works.SRM
             DB.Do(db =>
             {
                 var task = db.Default.Set<WCS_TASK>().Where(v => v.DEVICE == obj.Entity.CODE).Where(v => v.STATUS == TaskStatus.堆垛机执行).FirstOrDefault();
-                if (task != null) throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的任务:[{task.ID}]", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                if (task != null) throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的任务:[{task.ID}]", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                 //属于当前堆垛机未执行的移库任务
                 isTransfer = db.Default.Set<WCS_TASK>().AsNoTracking().Where(v => v.DEVICE == obj.Entity.CODE && v.TYPE == TaskType.移库 && v.STATUS < TaskStatus.堆垛机执行).ToList();
                 //判断是否存在调整优先级任务,存在初始化isTransfer值 让本次执行优先任务
@@ -134,23 +138,23 @@ namespace WCS.Service.Works.SRM
                         if (addrFrom[2].ToShort().OddNumberOrEven())
                         {
                             obj.Data.TaskID_1 = task.ID;
-                            obj.Data.SLine_1 = addrFrom[1].ToShort();
-                            obj.Data.SCol_1 = addrFrom[2].ToShort();
-                            obj.Data.SLayer_1 = addrFrom[3].ToShort();
-                            obj.Data.ELine_1 = addrTo[1].ToShort();
-                            obj.Data.ECol_1 = addrTo[2].ToShort();
-                            obj.Data.ELayer_1 = addrTo[3].ToShort();
+                            obj.Data.SLine_1 = addrFrom[0].ToShort();
+                            obj.Data.SCol_1 = addrFrom[1].ToShort();
+                            obj.Data.SLayer_1 = addrFrom[2].ToShort();
+                            obj.Data.ELine_1 = addrTo[0].ToShort();
+                            obj.Data.ECol_1 = addrTo[1].ToShort();
+                            obj.Data.ELayer_1 = addrTo[2].ToShort();
                             obj.Data.VoucherNo_1++;
                         }
                         else
                         {
                             obj.Data.TaskID_2 = task.ID;
-                            obj.Data.SLine_2 = addrFrom[1].ToShort();
-                            obj.Data.SCol_2 = addrFrom[2].ToShort();
-                            obj.Data.SLayer_2 = addrFrom[3].ToShort();
-                            obj.Data.ELine_2 = addrTo[1].ToShort();
-                            obj.Data.ECol_2 = addrTo[2].ToShort();
-                            obj.Data.ELayer_2 = addrTo[3].ToShort();
+                            obj.Data.SLine_2 = addrFrom[0].ToShort();
+                            obj.Data.SCol_2 = addrFrom[1].ToShort();
+                            obj.Data.SLayer_2 = addrFrom[2].ToShort();
+                            obj.Data.ELine_2 = addrTo[0].ToShort();
+                            obj.Data.ECol_2 = addrTo[1].ToShort();
+                            obj.Data.ELayer_2 = addrTo[2].ToShort();
                             obj.Data.VoucherNo_2++;
                         }
                         var oldTaskSTATUS = task.STATUS;
@@ -175,6 +179,8 @@ namespace WCS.Service.Works.SRM
                 // 获取可以到达目标巷道的取货点
                 var arrIn = Device.Where(v => v.PATHPOINTS.Any(p => p.NEXT == t)).Select(v => v.Create<StationDevice>()).ToArray();
 
+                arrIn = arrIn.Where(v => Device.Where(d => d.IsConv()).Select(d => d.Device<IStation521>()).Where(d => d.Data.Goodsend == v.Entity.Code()).Any()).ToArray();
+
                 if (arrIn.Length == 0) return; //无当前堆垛机的入库任务
 
                 //入库口设备信息 不是设备组
@@ -205,7 +211,8 @@ namespace WCS.Service.Works.SRM
                     {
                         var tunnel = dev1.Entity.ROUTES.First().NEXT.CODE;
                         var task1 = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.STATUS < TaskStatus.堆垛机执行 && v.ID == dev1.Data2.Tasknum);
-                        if (task1 == null) throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev1.Data2.Tasknum}", dev1.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常));
+                        if (task1 == null)
+                            throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev1.Data2.Tasknum}", dev1.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
                         var loc = WMS.GetLocalIn(task1.WMSTASK, tunnel, dev1.Entity.CODE, Entity.WareCellForkNum.货叉1);
                         var locno = string.Format("{0}-{1}-{2}", loc.Row, loc.Colomn, loc.Layer);
                         var oldTask = task1.STATUS;
@@ -231,7 +238,7 @@ namespace WCS.Service.Works.SRM
                     {
                         var tunnel = dev2.Entity.ROUTES.First().NEXT.CODE;
                         var task2 = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.STATUS < TaskStatus.堆垛机执行 && v.ID == dev2.Data2.Tasknum);
-                        if (task2 == null) throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev2.Data2.Tasknum}", dev2.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常));
+                        if (task2 == null) throw new Exception(LogHelper.SpliceLogMessage($"设备有光电有任务且不在运行状态,但WCS找不到任务{dev2.Data2.Tasknum}", dev2.Entity.CODE, WCS_EXCEPTIONTYPE.设备异常, GetType()));
                         var loc = WMS.GetLocalIn(task2.WMSTASK, tunnel, dev2.Entity.CODE, Entity.WareCellForkNum.货叉2);
                         var locno = string.Format("{0}-{1}-{2}", loc.Row, loc.Colomn, loc.Layer);
                         var oldTask = task2.STATUS;
@@ -319,12 +326,12 @@ namespace WCS.Service.Works.SRM
                 {
                     //堆垛机当前是否有正在执行的任务
                     if (db.Default.Set<WCS_TASK>().Any(d => d.DEVICE == sc && d.STATUS == TaskStatus.堆垛机执行))
-                        throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的出库任务", deviceCode, WCS_EXCEPTIONTYPE.逻辑异常));
+                        throw new Exception(LogHelper.SpliceLogMessage($"[{deviceCode}]有正在执行的出库任务", deviceCode, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                     //找出等待执行的出库任务
                     var q = db.Default.Set<WCS_TASK>().Where(v => v.STATUS == TaskStatus.新建)
                                                       .Where(v => v.DEVICE == sc)
                                                       .Where(v => v.TYPE == TaskType.出库)
-                                                      .Where(v => !db.Default.Set<WCS_TASK>().Any(d => d.DEVICE == sc && d.STATUS == TaskStatus.堆垛机执行));
+                                                      .Where(v => !db.Default.Set<WCS_TASK>().Any(d => d.DEVICE == sc && d.STATUS == TaskStatus.堆垛机执行)).ToList();
                     //同一个目标地址同时只能有4(双工位,每一节设备可以存放两个任务)个正在执行的任务
                     //考虑到有可能出现一次只发一个任务的情况,因此判断条件为3
                     //连续两次只发一个任务的情况暂时不考虑
@@ -349,50 +356,65 @@ namespace WCS.Service.Works.SRM
                         return;
                     }
                     //获取两个个可执行任务,此时这两个任务的目标地址是一致的
-                    var tasks = item.Select(v => v).Take(2);
+                    var tasks = item.Select(v => v).ToList().GetOutTask();
+
                     //根据任务的目标地址获取对应的设备组
-                    var devs = Device.Find($"G{tasks.OrderBy(v => v.ADDRTO).FirstOrDefault().ADDRTO}").Create<StationDeviceGroup>().Items.OrderByDescending(v => v.Entity.CODE).ToArray();
+                    var devs = Device.Find($"{tasks.OrderBy(v => v.ADDRTO).FirstOrDefault().ADDRTO}").Create<StationDeviceGroup>().Items.OrderByDescending(v => v.Entity.CODE).ToArray();
                     var dev1 = devs[0];
                     var dev2 = devs[1];
 
                     foreach (var task in tasks)
                     {
-                        var next = "";
                         //判断当前任务为二工位还是一工位
                         var addrFrom = task.ADDRFROM.Split("-");
-                        if (addrFrom[2].ToShort().OddNumberOrEven())
-                        {
-                            obj.Data.TaskID_2 = task.ID;
-                            obj.Data.SLine_2 = addrFrom[0].ToShort();
-                            obj.Data.SCol_2 = addrFrom[1].ToShort();
-                            obj.Data.SLayer_2 = addrFrom[2].ToShort();
-                            obj.Data.ELine_2 = dev2.Entity.CODE.ToShort();
-                            obj.Data.ECol_2 = 0;
-                            obj.Data.ELayer_2 = 0;
-                            obj.Data.VoucherNo_2++;
-                            next = dev2.Entity.CODE;
-                        }
-                        else
+
+                        if (addrFrom[1].ToShort().OddNumberOrEven())
                         {
+                            InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]1工位-开始:[{obj.Data.TaskID_1}][{obj.Data.SLine_1}][{obj.Data.SCol_1}][{obj.Data.SLayer_1}][{obj.Data.ELine_1}][{obj.Data.VoucherNo_1}]");
                             obj.Data.TaskID_1 = task.ID;
                             obj.Data.SLine_1 = addrFrom[0].ToShort();
                             obj.Data.SCol_1 = addrFrom[1].ToShort();
                             obj.Data.SLayer_1 = addrFrom[2].ToShort();
-                            obj.Data.ELine_1 = dev1.Entity.CODE.ToShort();
+                            obj.Data.ELine_1 = task.SRMSTATION.ToShort();
                             obj.Data.ECol_1 = 0;
                             obj.Data.ELayer_1 = 0;
                             obj.Data.VoucherNo_1++;
-                            next = dev1.Entity.CODE;
+                            InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]1工位-结束:[{obj.Data.TaskID_1}][{obj.Data.SLine_1}][{obj.Data.SCol_1}][{obj.Data.SLayer_1}][{obj.Data.ELine_1}][{obj.Data.VoucherNo_1}]");
+                        }
+                        else
+                        {
+                            InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]2工位-开始:[{obj.Data.TaskID_2}][{obj.Data.SLine_2}][{obj.Data.SCol_2}][{obj.Data.SLayer_2}][{obj.Data.ELine_2}][{obj.Data.VoucherNo_2}]");
+                            obj.Data.TaskID_2 = task.ID;
+                            obj.Data.SLine_2 = addrFrom[0].ToShort();
+                            obj.Data.SCol_2 = addrFrom[1].ToShort();
+                            obj.Data.SLayer_2 = addrFrom[2].ToShort();
+                            obj.Data.ELine_2 = task.SRMSTATION.ToShort();
+                            obj.Data.ECol_2 = 0;
+                            obj.Data.ELayer_2 = 0;
+                            obj.Data.VoucherNo_2++;
+                            InfoLog.INFO_SRMINFO($"写入堆垛机[{obj.Entity.CODE}]2工位-结束:[{obj.Data.TaskID_2}][{obj.Data.SLine_2}][{obj.Data.SCol_2}][{obj.Data.SLayer_2}][{obj.Data.ELine_2}][{obj.Data.VoucherNo_2}]");
                         }
                         var oldTaskSTATUS = task.STATUS;
                         task.STARTTIME = DateTime.Now;
                         task.UPDATETIME = DateTime.Now;
                         task.STATUS = WCS.Entity.TaskStatus.堆垛机执行;
                         task.DEVICE = obj.Entity.CODE;
-                        task.ADDRNEXT = next;
+                        //获取到站台的下一个地址
+                        if (Device.Find(task.SRMSTATION).ROUTES.Any(v => v.NEXT == dev1.Entity)) task.ADDRNEXT = dev1.Entity.CODE;
+                        else task.ADDRNEXT = dev2.Entity.CODE;
+
                         db.Default.SaveChanges();
                         Uploader.Upload(db);
-                        task.CreateStatusLog(db, $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}]", this.GetType());
+                        if (addrFrom[1].ToShort().OddNumberOrEven())
+                        {
+                            var msg = $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}][{obj.Data.SLine_1}-{obj.Data.SCol_1}-{obj.Data.SLayer_1}][{obj.Data.ELine_1}][{obj.Data.VoucherNo_1}]";
+                            task.CreateStatusLog(db, msg, this.GetType());
+                        }
+                        else
+                        {
+                            var msg = $"状态由[{oldTaskSTATUS}]变更为[{task.STATUS}][{obj.Data.SLine_2}-{obj.Data.SCol_2}-{obj.Data.SLayer_2}][{obj.Data.ELine_2}][{obj.Data.VoucherNo_2}]";
+                            task.CreateStatusLog(db, msg, this.GetType());
+                        }
                     }
                 });
 

+ 64 - 40
Projects/永冠OPP/WCS.Service/Works/Station/一楼入库.cs

@@ -1,9 +1,11 @@
 using DBHelper;
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using WCS.Core;
 using WCS.Entity;
 using WCS.Entity.Protocol;
+using WCS.Entity.Protocol.SRM;
 using WCS.Service.Extensions;
 using WCS.Service.Helpers;
 
@@ -27,7 +29,7 @@ namespace WCS.Service.Works.Station
 
             var bcr = dev.Entity.BCR();
             var barcode = bcr.Content.Trim('\r');
-            if (barcode == "") throw new Exception(LogHelper.SpliceLogMessage("扫码失败", dev.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+            if (barcode == "") throw new Exception(LogHelper.SpliceLogMessage("扫码失败", dev.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
 
             var info = WMS.I_WCS_GetInTask(barcode, dev.Entity.CODE);
             var next = dev.Entity.CODE == Conv_1028 ? "1030" : "1031";
@@ -68,6 +70,8 @@ namespace WCS.Service.Works.Station
     internal class 巷道分配 : Work<StationDeviceGroup>
     {
         private readonly string ConvGroup_1030 = "G1030";
+        private readonly string Conv_1030 = "1030";
+        private readonly string RGV8 = "RGV8";
 
         protected override bool SelectDevice(WCS_DEVICE dev)
         {
@@ -81,48 +85,50 @@ namespace WCS.Service.Works.Station
             if (obj.WhetherToExecute(IstationRequest.请求分配目标地址)) return;
 
             //获取需要进行巷道分配的设备
-            var devs = obj.TaskedDeviceGetNextAddress() ?? throw new Exception(LogHelper.SpliceLogMessage("无可用任务", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+            var devs = obj.TaskedDeviceGetNextAddress() ?? throw new Exception(LogHelper.SpliceLogMessage("无可用任务", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
 
             DB.Do(db =>
             {
                 var taskIds = devs.Select(p => p.Data2.Tasknum);
                 var tasks = db.Default.Set<WCS_TASK>().Where(p => taskIds.Any(v => v == p.ID)).ToList();
                 var res = WMS.GetTunnelList(tasks.Select(v => v.WMSTASK.ToString()).ToList(), code);
-                var tunnels = res.TunnelNum.Split(',').Select(v => "TY" + v).ToList();
-                //var tunnels = "5,6".Split(',').Select(v => "TY" + v).ToList();
+                if (string.IsNullOrEmpty(res.TunnelNum)) throw new Exception(LogHelper.SpliceLogMessage($"WMS未返回巷道", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+                var tunnelNo = res.TunnelNum.Split(',').Select(v => "TY" + v).ToList();
 
+                var tunnels = Device.Where(v => tunnelNo.Contains(v.CODE)).ToList();
+                List<TunnelInfo> tunnelInfos = new List<TunnelInfo>();
+                foreach (var item in tunnels)
+                {
+                    //找到空闲的取货点 先找到下一个路径点是当前巷道的设备
+                    var q = Device.Where(p => p.PATHPOINTS.Any(d => d.NEXT == item))
+                                    .SelectMany(p => p.PATHPOINTS) //将所有取货点的路线信息提取到一个集合中
+                                    .Select(p => p.PREV.Create<StationDevice>())//取出所有取货点的前一个路径点
+                                    .Where(p => !p.Data3.Status.HasFlag(StationStatus.运行状态位) && !p.Data2.Status.HasFlag(IstationStatus.光电状态) && p.Data2.Tasknum < 10000)//筛选出空闲的路径点,此处因输送机都是一个动力,因此可以先找路径点再找设备组
+                                    .Where(p => Device.Where(d => d.CODE.StartsWith("G")).Any(d => d.DEVICEGROUP.Any(c => c.MEMBER == p.Entity)))//找到有效路径点对应的设备组
+                                    .Distinct().FirstOrDefault();//去一次重
+                    if (q == null) continue;
+                    var dev = Device.Where(p => p.CODE.StartsWith("G") && p.DEVICEGROUP.Any(d => d.MEMBER == q.Entity)).OrderBy(p => p.CODE).FirstOrDefault();
+
+                    tunnelInfos.Add(new TunnelInfo
+                    {
+                        Tunnel = item,
+                        taskIN = dev, //找到放货点设备所在组
+                        SRM = Device.Where(p => p.IsSC()).FirstOrDefault(p => item.ROUTES.Any(d => d.NEXT.CODE == p.CODE)).Create<SRMDevice>()
+                    });
+                }
                 //筛选出优先级最高的可用巷道
-                var tunnelInfo = Device.Where(v => tunnels.Contains(v.CODE)).Select(v =>
-                                        {
-                                            var a = Device.Where(p => p.PATHPOINTS.Any(d => d.NEXT == v))
-                                                            .SelectMany(p => p.PATHPOINTS) //将所有取货点的路线信息提取到一个集合中
-                                                            .Select(p => p.PREV.Create<StationDevice>())//取出所有取货点的前一个路径点
-                                                            .Where(p => !p.Data3.Status.HasFlag(StationStatus.运行状态位) && !p.Data2.Status.HasFlag(IstationStatus.光电状态) && p.Data2.Tasknum < 10000);
-
-                                            //找到空闲的取货点 先找到下一个路径点是当前巷道的设备
-                                            var dev = Device.Where(p => p.PATHPOINTS.Any(d => d.NEXT == v))
-                                                            .SelectMany(p => p.PATHPOINTS) //将所有取货点的路线信息提取到一个集合中
-                                                            .Select(p => p.PREV.Create<StationDevice>())//取出所有取货点的前一个路径点
-                                                            .Where(p => !p.Data3.Status.HasFlag(StationStatus.运行状态位) && !p.Data2.Status.HasFlag(IstationStatus.光电状态) && p.Data2.Tasknum < 10000)//筛选出空闲的路径点,此处因输送机都是一个动力,因此可以先找路径点再找设备组
-                                                            .Where(p => Device.Where(d => d.CODE.StartsWith("G")).Any(d => d.DEVICEGROUP.Any(c => c.MEMBER == p.Entity)))//找到有效路径点对应的设备组
-                                                            .Distinct().FirstOrDefault().Entity;//去一次重
-                                            dev = Device.Where(p => p.CODE.StartsWith("G") && p.DEVICEGROUP.Any(d => d.MEMBER == dev)).OrderBy(p => p.CODE).FirstOrDefault();
-                                            return new TunnelInfo
-                                            {
-                                                Tunnel = v,
-                                                taskIN = dev, //找到放货点设备所在组
-                                                SRM = Device.Where(p => p.IsSC()).FirstOrDefault(p => v.ROUTES.Any(d => d.NEXT.CODE == p.CODE)).Create<SRMDevice>()
-                                            };
-                                        })
-                                        //TODO:正式使用时必须启用这下一行的堆垛机状态判断
-                                        //.Where(v => v.SRM.Data2.Alarm_1 == false && v.SRM.Data2.Alarm_2 && v.SRM.Data2.Mode_1 == SCMode.远程 && v.SRM.Data2.Mode_2 == SCMode.远程)
-                                        .OrderBy(v => tunnels.IndexOf(v.Tunnel.CODE)).FirstOrDefault();
+                var tunnelInfo = tunnelInfos.Where(v => { try { return v.SRM.Data3.SCAlarm == 0 && v.SRM.Data2.SRMMode == SCMode.远程; } catch { return false; } })
+                                            .OrderBy(v => tunnelNo.IndexOf(v.Tunnel.CODE)).FirstOrDefault();
+                if (tunnelInfo == null) throw new Exception(LogHelper.SpliceLogMessage("无可用巷道", obj.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
+
                 //开始向设备中写入任务信息
                 foreach (var dev in devs)
                 {
                     var task = tasks.FirstOrDefault(p => p.ID == dev.Data2.Tasknum);
+                    if ((task.TaskGroupKey.Contains($"{task.WMSTASK}_") || task.TaskGroupKey.Contains($"_{task.WMSTASK}")) && dev.Data2.Goodsend == task.ADDRNEXT.ToShort()) continue;
+                    if (dev.Data2.Request != IstationRequest.请求分配目标地址) continue;
                     dev.Data.Tasknum = task.ID;
-                    dev.Data.Goodsstart = dev.Entity.CODE.ToShort();
+                    dev.Data.Goodsstart = Conv_1030.ToShort();
                     dev.Data.Goodsend = tunnelInfo.taskIN.CODE.Replace("G", "").ToShort();
                     dev.Data.CmdType = IstationCmdType.分配目标地址;
                     dev.Data.VoucherNo++;
@@ -134,20 +140,13 @@ namespace WCS.Service.Works.Station
                     task.ADDRTO = task.DEVICE;
                     db.Default.SaveChanges();
 
-                    var msg = $"下达从{dev.Data.Goodsstart}移动至{dev.Data.Goodsend}的PLC指令。同时将任务分配至[{ task.TUNNEL }]-[{task.DEVICE}]";
-                    msg += $"[{dev.Data.Tasknum}][{dev.Data.Goodsstart}][{dev.Data.Goodsend}][{dev.Data.VoucherNo}[{dev.Data2.VoucherNo}]";
+                    var msg = $"下达从{Conv_1030}移动至{dev.Data.Goodsend}的PLC指令。同时将任务分配至[{ task.TUNNEL }]-[{task.DEVICE}]";
+                    msg += $"[{dev.Data.Tasknum}][{Conv_1030}][{dev.Data.Goodsend}][{tunnelInfo.SRM.Entity.CODE}][{dev.Data.VoucherNo}[{dev.Data2.VoucherNo}]";
 
                     task.CreateStatusLog(db, msg, this.GetType());
                 }
             });
         }
-
-        private class TunnelInfo
-        {
-            public WCS_DEVICE Tunnel;
-            public WCS_DEVICE taskIN;
-            public Device<ISRM520, ISRM521, ISRM537> SRM;
-        }
     }
 
     [WorkTitle(typeof(ProductHandler), "一楼RGV放货结束分配目标地址")]
@@ -161,6 +160,17 @@ namespace WCS.Service.Works.Station
             DB.Do(db =>
             {
                 var task = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.ID == obj.Data2.Tasknum);
+                switch (task.ADDRFROM)
+                {
+                    case "1028":
+                        break;
+
+                    case "1029":
+                        break;
+
+                    default:
+                        break;
+                }
                 var next = obj.Entity.GetPath(task.ADDRTO);
 
                 obj.Data.Tasknum = task.ID;
@@ -169,6 +179,9 @@ namespace WCS.Service.Works.Station
                 obj.Data.CmdType = IstationCmdType.分配目标地址;
                 obj.Data.VoucherNo++;
 
+                task.ADDRNEXT = next.FirstOrDefault().CODE;
+                db.Default.SaveChanges();
+
                 var msg = $"下达从{obj.Data.Goodsstart}移动至{obj.Data.Goodsend}的PLC指令";
                 msg += $"[{obj.Data.Tasknum}][{obj.Data.Goodsstart}][{obj.Data.Goodsend}][{obj.Data.VoucherNo}[{obj.Data2.VoucherNo}]";
 
@@ -178,7 +191,18 @@ namespace WCS.Service.Works.Station
 
         protected override bool SelectDevice(WCS_DEVICE dev)
         {
-            return dev.CODE == "1035" || dev.CODE == "1036";
+            return devCodes.Contains(dev.CODE);
         }
+
+        private List<string> devCodes = new List<string>() {
+            "1035",
+            "1036",
+            "1044",
+            "1045",
+            "1053",
+            "1054",
+            "1062",
+            "1063",
+        };
     }
 }

+ 17 - 5
Projects/永冠OPP/WCS.Service/Works/Station/一楼出库.cs

@@ -18,13 +18,18 @@ namespace WCS.Service.Works.Station
             //找到当前站台为当前设备且任务为堆垛机完成的任务
             DB.Do(db =>
             {
-                var task = db.Default.Set<WCS_TASK>().Single(v => v.SRMSTATION == obj.Entity.CODE && v.STATUS == TaskStatus.堆垛机完成);
+                var task = db.Default.Set<WCS_TASK>().FirstOrDefault(v => v.TYPE == TaskType.出库 && v.SRMSTATION == obj.Entity.CODE && v.STATUS == TaskStatus.堆垛机完成);
+                if (task == null) return;
+                if (task.SRMSTATION != obj.Entity.CODE && task.STATUS != TaskStatus.堆垛机完成) return;
+                task.STATUS = TaskStatus.执行中;
+                db.Default.SaveChanges();
                 //开始写入目标地址
                 obj.Data.Tasknum = task.ID;
                 obj.Data.Goodsstart = obj.Entity.CODE.ToShort();
                 obj.Data.Goodsend = task.ADDRNEXT.ToShort();
                 obj.Data.CmdType = IstationCmdType.堆垛机放货完成请求目标地址;
                 obj.Data.VoucherNo++;
+                task.CreateStatusLog(db, $"状态由[{TaskStatus.堆垛机完成}]变更为[{task.STATUS}]-{obj.Entity.Code}", this.GetType());
             });
         }
 
@@ -39,20 +44,27 @@ namespace WCS.Service.Works.Station
     {
         protected override void Do(StationDeviceGroup obj)
         {
-            if (obj.WhetherToExecute()) return;
             //找到当前站台为当前设备且任务为堆垛机完成的任务
             DB.Do(db =>
             {
                 foreach (var dev in obj.Items)
                 {
+                    //当前组有一个运行的设备就停止执行
+                    if (dev.Data3.Status.HasFlag(StationStatus.运行状态位)) continue;
+                    if (dev.Data2.Status.HasFlag(IstationStatus.光电状态)) continue;
                     if (dev.Data2.Tasknum < 10000) continue;
-                    if (dev.Data2.Request != IstationRequest.月台出库口任务完成) continue;
-                    var task = db.Default.Set<WCS_TASK>().Find(dev.Data2.Tasknum);
-                    if (task.STATUS != TaskStatus.堆垛机完成) throw new Exception(LogHelper.SpliceLogMessage($"{task.ID}任务状态错误", dev.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常));
+                    if (dev.Data2.Request != IstationRequest.月台出库口任务完成)
+                    {
+                        continue;
+                    }
+                    var task = db.Default.Set<WCS_TASK>().Where(v => v.ID == dev.Data2.Tasknum).FirstOrDefault();
+                    if (task.STATUS != TaskStatus.执行中)
+                        throw new Exception(LogHelper.SpliceLogMessage($"{task.ID}任务状态错误", dev.Entity.CODE, WCS_EXCEPTIONTYPE.逻辑异常, GetType()));
                     task.STATUS = TaskStatus.已完成;
                     db.Default.SaveChanges();
                     dev.Data.CmdType = IstationCmdType.月台出库口任务完成;
                     dev.Data.VoucherNo++;
+                    task.CreateStatusLog(db, $"状态由[{TaskStatus.执行中}]变更为[{task.STATUS}]-{dev.Entity.CODE}", this.GetType());
                 }
             });
         }

+ 40 - 0
Projects/永冠OPP/WCS.Service/config.json

@@ -0,0 +1,40 @@
+{
+  "LogPath": "D:\\WCSLog\\", // ÈÕ־Ŀ¼
+  "LogDays": 30,
+  "LogSize": 100,
+  "Logs": [
+    {
+      "Name": "Info",
+      "FileName": "D:\\WCSLog\\",
+      "SubLogNames": {
+        "INFO_INIT": "Info_Init",
+        "INFO_SRMALARM": "Info_SrmAlarm",
+        "INFO_INFO": "Info_Info",
+        "INFO_ERROR": "Info_Error",
+        "INFO_SRMINFO": "Info_SRMInfo",
+        "INFO_SYTASKSTATUS": "Info_SyTaskTatus",
+        "INFO_WMSREQUEST": "INFO_WMSRequest"
+      }
+    },
+    {
+      "Name": "Error",
+      "FileName": "D:\\WCSLog\\",
+      "SubLogNames": {
+      }
+    },
+    {
+      "Name": "Warn",
+      "FileName": "D:\\WCSLog\\",
+      "SubLogNames": {
+      }
+    },
+    {
+      "Name": "Db",
+      "FileName": "D:\\WCSLog\\",
+      "SubLogNames": {
+        "DBEX": "Db_Ex",
+        "DB_CLEAN": "Db_Clean"
+      }
+    }
+  ]
+}

+ 1 - 1
WCS.Core/LogicHandler.cs

@@ -310,7 +310,7 @@ namespace WCS.Core
                 var con = ex.GetBaseException().Message.Split("|");
 
                 msg = msg + ":" + con[0];
-                Console.WriteLine(msg);
+                //Console.WriteLine(msg);
 
                 DbLog.Invoke(msg, con[1], con[2]);
             }