| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989 | 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.RGV;using WCS.Service.Helpers;using WCS.Service.Log;namespace WCS.Service.Extensions{    /// <summary>    /// 输送机设备组    /// </summary>    public class StationDeviceGroup : DeviceGroup<IStation520, IStation521, IStation523>    {        /// <summary>        /// 当前设备可用的RGV        /// </summary>        private static List<RGVDevice> AllRGVList;        static StationDeviceGroup()        {            AllRGVList = Device.Where(v => v.IsRGV() && v.CODE != "RGV8").Select(v => v.Create<RGVDevice>()).ToList();        }        public StationDeviceGroup(WCS_DEVICE entity) : base(entity)        {        }        /// <summary>        /// 执行输送机设备组任务 单例锁        /// </summary>        /// <param name="act"></param>        public void EX(Action<StationDeviceGroup> act)        {            try            {                if (ExDevice.Any(v => v == Entity.CODE)) throw new WarnException($"[{Entity.CODE}]--触发并发管控");                OperateExDevice(Entity.CODE);                act(this);            }            catch (DoException ex)            {                ex.DoExceptionEX(Entity);            }            catch (WarnException ex)            {                ex.WarnExceptionEX(Entity);            }            catch (Exception ex)            {                ex.ExceptionEx(Entity);            }            finally            {                OperateExDevice(Entity.CODE);            }        }        /// <summary>        /// 当前设备可用的RGV        /// </summary>        public List<RGVDevice> RgvList        {            get            {                return AllRGVList.Where(v => v.LocationList.Any(p => p.Entity == Entity)).ToList();            }        }        /// <summary>        /// 当前设备环穿组        /// </summary>        private List<StationLocation> LoncationList        {            get            {                var dev = StationLocation.ALLlocations.FirstOrDefault(v => v.Station == Entity.CODE);                return StationLocation.ALLlocations.Where(v => v.PLC == dev.PLC).ToList();            }        }        /// <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>        /// 设备组是否满足任务执行条件        /// </summary>        /// <param name="type">给当前设备组下发任务时需要的请求</param>        /// <returns>true:不满足执行条件需要进行停止执行  false:表示满足条件不需要停止执行 </returns>        /// <exception cref="Exception"></exception>        public void WhetherToExecute(IstationRequest type = IstationRequest.无)        {            foreach (var item in Items)            {                if (item.Data.VoucherNo != item.Data2.VoucherNo) throw new WarnException($"等待{item.Entity.CODE}执行任务{item.Data.Tasknum},凭证号不一致");                if (item.Data3.Status.HasFlag(StationStatus.运行状态位)) throw new DoException($"{item.Entity.CODE}运行中");                if (!item.Data2.Status.HasFlag(IstationStatus.光电状态)) throw new DoException($"[{item.Entity.CODE}]无光电");            }        }        /// <summary>        /// 获取设备组中需要取货的设备        /// </summary>        /// <param name="obj"></param>        /// <returns></returns>        public List<Device<IStation520, IStation521, IStation523>> RGVGetTaskedDevice()        {            var a = Items.Where(v => v.Data2.Status.HasFlag(IstationStatus.光电状态) && v.Data2.Tasknum > 10000)                        .Where(v => v.Entity.CODE.ToShort() != v.Data2.Goodsend && v.Data2.Goodsend != 0)                        .ToList();            return a.Count == 0 ? null : a;        }        /// <summary>        /// 获取设备组中需要分配目标地址的设备        /// </summary>        /// <param name="obj"></param>        /// <returns></returns>        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 != 0)                        .ToList();            return a.Count == 0 ? null : a;        }        /// <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 DevEX.Distance(Position, rgv.Position, Length);        }        /// <summary>        /// 计算两个站台之间的距离        /// </summary>        /// <param name="rgv"></param>        /// <returns></returns>        public float Distance(StationDeviceGroup dev)        {            return DevEX.Distance(Position, dev.Position, Length);        }        /// <summary>        /// 当前RGV        /// </summary>        /// <returns></returns>        public RGVDevice CurrentRGV()        {            //RGV与站台距离误差为 正负50            var max = Position + 500;            var min = Position - 500;            return RgvList?.FirstOrDefault(v => v.Data2.Position < max && v.Data2.Position > min);        }        /// <summary>        /// 是否需要RGV        /// </summary>        /// <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 WarnException("已有RGV执行中");            foreach (var item in Items)            {                if (item.Data3.Status.HasFlag(StationStatus.运行状态位)) return false;                if (!item.Data2.Status.HasFlag(IstationStatus.光电状态)) return false;            }            return true;        }    }    /// <summary>    /// 输送机设备    /// </summary>    public class StationDevice : Device<IStation520, IStation521, IStation523>    {        public StationDevice(WCS_DEVICE entity) : base(entity)        {        }        /// <summary>        /// 设备组是否满足任务执行条件        /// </summary>        /// <param name="type">给当前设备组下发任务时需要的请求</param>        /// <returns>true:不满足执行条件需要进行停止执行  false:表示满足条件不需要停止执行 </returns>        /// <exception cref="Exception"></exception>        public void WhetherToExecute(IstationRequest type = IstationRequest.无)        {            //正在运行            if (Data3.Status.HasFlag(StationStatus.运行状态位)) throw new DoException("运行中");            //上一次的任务还未执行            if (Data.VoucherNo != Data2.VoucherNo)                throw new WarnException($"等待任务[{Data2.Tasknum}]执行");            //没有光电            if (!Data2.Status.HasFlag(IstationStatus.光电状态)) throw new DoException("无光电"); ;            //没有任务号            switch (type)            {                case IstationRequest.无:                    if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)                        throw new WarnException($"设备无任务");                    break;                case IstationRequest.扫码入库:                    if (Data2.Tasknum > 10000 && Data.Tasknum > 10000)                        throw new WarnException($"设备已有任务任务");                    break;                case IstationRequest.堆垛机放货完成请求目标地址:                    if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)                        throw new WarnException($"设备无任务信息");                    break;                case IstationRequest.请求分配目标地址:                    if (Data2.Tasknum < 10000 && Data.Tasknum < 10000)                        throw new WarnException($"设备无任务信息");                    break;            }            //没有请求            if (type != IstationRequest.无 && Data2.Request != type)                throw new WarnException($"有光电无{type}请求");        }        /// <summary>        /// 执行输送机任务 单例锁        /// </summary>        /// <param name="act"></param>        public void EX(Action<StationDevice> act)        {            try            {                if (ExDevice.Any(v => v == Entity.CODE)) throw new WarnException($"[{Entity.CODE}]--触发并发管控");                OperateExDevice(Entity.CODE);                act(this);            }            catch (DoException ex)            {                ex.DoExceptionEX(Entity);            }            catch (WarnException ex)            {                ex.WarnExceptionEX(Entity);            }            catch (Exception ex)            {                ex.ExceptionEx(Entity);            }            finally            {                OperateExDevice(Entity.CODE);            }        }    }    /// <summary>    /// RGV设备    /// </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();        }        public RGVDevice(WCS_DEVICE entity) : base(entity)        {        }        /// <summary>        /// 所有环穿RGV        /// </summary>        private static List<RGVDevice> AllRGVList { get; set; }        /// <summary>        /// 与当前RGV处于同一环穿的RGV        /// </summary>        public List<RGVDevice> RGVList        {            get            {                return AllRGVList.Where(v => v.Entity.PROTOCOLS.Any(d => Entity.PROTOCOLS.Any(e => e.DB.PLC.IP == d.DB.PLC.IP)))                    .Where(v => v.Entity.CODE != Entity.CODE).ToList();            }        }        /// <summary>        /// RGV当前位置        /// </summary>        public float Position        {            get            {                return Data2.Position;            }        }        /// <summary>        /// 与当前RGV处于同一环穿的站台        /// </summary>        public List<StationDeviceGroup> LocationList        {            get            {                return StationLocation.ALLlocations.Where(v => Entity.PROTOCOLS.Any(p => p.DB.PLC.CODE == v.PLC))                                      .Select(v => Device.Find(v.Station).Create<StationDeviceGroup>()).ToList();            }        }        /// <summary>        /// 总长度        /// </summary>        public float Length        {            get            {                return LocationList.FirstOrDefault().Length;            }        }        /// <summary>        /// 执行RGV任务 单例锁        /// </summary>        /// <param name="act"></param>        public void EX(Action<RGVDevice> act)        {            try            {                if (ExDevice.Any(v => v == Entity.CODE)) throw new WarnException($"[{Entity.CODE}]--触发并发管控");                OperateExDevice(Entity.CODE);                act(this);            }            catch (DoException ex)            {                ex.DoExceptionEX(Entity);            }            catch (WarnException ex)            {                ex.WarnExceptionEX(Entity);            }            catch (Exception ex)            {                ex.ExceptionEx(Entity);            }            finally            {                OperateExDevice(Entity.CODE);            }        }        /// <summary>        /// 获取前一个取货点        /// </summary>        /// <returns></returns>        public StationDeviceGroup BeforeStation()        {            return LocationList.Where(v => v.Entity.Is(DF.涂布RGV取货设备组)).OrderBy(v => Distance(v)).FirstOrDefault();        }        /// <summary>        /// 前一个RGV        /// </summary>        /// <returns></returns>        public RGVDevice Before()        {            //按照位置排序            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        /// </summary>        /// <returns></returns>        public RGVDevice After()        {            //到当前RGV最近的一个RGV            return RGVList.OrderBy(v => v.Distance(this)).FirstOrDefault();        }        /// <summary>        /// 获取当前所在的取货站台        /// </summary>        /// <returns></returns>        public StationDeviceGroup CurrentStation()        {            return LocationList.Where(v => v.Entity.Is(DF.涂布RGV取货设备组) || v.Entity.Is(DF.涂布RGV放货设备组)).Where(v =>               {                   //RGV与站台距离误差为 正负50500                   var max = v.Position + 500;                   var min = v.Position - 500;                   return Data2.Position < max && Data2.Position > min;               }).FirstOrDefault();        }        /// <summary>        /// 计算当前RGV与指定RGV之间的距离        /// </summary>        /// <param name="rgv"></param>        /// <returns></returns>        public float Distance(RGVDevice rgv)        {            //return Math.Abs((Position - rgv.Position + Length) % Length);            return DevEX.Distance(Position, rgv.Position, Length);        }        /// <summary>        /// 计算当前RGV与指定R站台之间的距离        /// </summary>        /// <param name="after"></param>        /// <returns></returns>        public float Distance(StationDeviceGroup after)        {            return DevEX.Distance(Position, after.Position, Length);        }        /// <summary>        /// 是否需要执行放货任务        /// </summary>        /// <returns></returns>        public bool IsPut()        {            if (Data2.TaskType_1 != RGVTaskType.取货) return false;            if (!Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.RGV到站)) return false;            if (!Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.任务完成)) return false;            if (!Data2.Status_1.HasFlag(WCS.Entity.Protocol.RGVStatus.光电)) return false;            return true;        }        /// <summary>        /// 写入移动任务        /// </summary>        /// <param name="addr">目标地址</param>        public void Move(StationDeviceGroup addr)        {            if (Data2.WorkMode != RGVMode.自动) throw new WarnException($"RGV状态{Data2.WorkMode},无法执行移动任务");            if (Data2.SystemStatus != RGVRunStatus.空闲) throw new WarnException($"rgv状态为{Data2.SystemStatus},无法执行移动任务");            Data.TaskID_1 = addr.Entity.CODE.Replace("G", "").ToShort();            Data.TaskType_1 = RGVTaskType.移动;            Data.DestPosition_1 = addr.Entity.CODE.Replace("G", "").ToShort();            Data.Trigger_1++;        }        /// <summary>        /// 写入取货任务        /// </summary>        /// <param name="addr">目标地址</param>        public void Pick(StationDeviceGroup addr, int task1 = 0, int task2 = 0)        {            Data.TaskType_1 = RGVTaskType.取货;            Data.DestPosition_1 = addr.Entity.CODE.ToShort();            if (task1 != 0) Data.TaskID_1 = task1;            if (task2 != 0) Data.TaskID_2 = task2;            Data.Trigger_1++;        }        /// <summary>        /// 写入放货任务        /// </summary>        /// <param name="addr">目标地址</param>        public void Put(StationDeviceGroup addr, int task1 = 0, int task2 = 0)        {            Data.TaskType_1 = RGVTaskType.放货;            Data.DestPosition_1 = addr.Entity.CODE.Replace("G", "").ToShort();            if (task1 != 0) Data.TaskID_1 = task1;            if (task2 != 0) Data.TaskID_2 = task2;            Data.Trigger_1++;        }        /// <summary>        /// 筛选出所有与当前RGV距离小于指定长度的RGV        /// </summary>        /// <param name="distance">指定长度</param>        /// <returns></returns>        public RGVDevice[] RgvAfter(float distance)        {            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 (this.Distance(station) < rgv.Distance(station)) || station.CurrentRGV()?.Entity.CODE == this.Entity.CODE;        }        /// <summary>        /// 获取当前RGV的下一个站台,即距离最近的一个站台        /// </summary>        /// <returns></returns>        public StationDeviceGroup NextStation()        {            //先取当前RGV与所有站台的距离            var dev = LocationList.OrderBy(v => v.Distance(this)).FirstOrDefault();            return dev;        }    }    /// <summary>    /// 堆垛机设备    /// </summary>    public class SRMDevice : Device<ISRM520, ISRM521, ISRM537>    {        public SRMDevice(WCS_DEVICE entity) : base(entity)        {        }        /// <summary>        /// 获取放货点        /// </summary>        public List<StationDevice> GetDeliveryPoint()        {            return Entity.ROUTES.Select(v => v.NEXT) //巷道                                .SelectMany(v => v.ROUTES.Select(d => d.NEXT)) //放货点                                .Where(v => v.IsConv()) //必须是输送线                                .Select(v => v.Create<StationDevice>()).ToList();        }        /// <summary>        /// 获取取货点        /// </summary>        public List<StationDevice> GetPickPoint()        {            return Device.Where(v => v.Is(DF.SRM二级品取货) || v.Is(DF.SRM涂布取货))                         .Where(v => v.ROUTES.Any(p => p.NEXT.ROUTES.Any(d => d.NEXT == Entity)))                         .Select(v => v.Create<StationDevice>())                         .ToList();        }        /// <summary>        /// 处理完成任务        /// </summary>        public void FinishedTaskHandle()        {            WCS_TASK task = new WCS_TASK();            DB.Do(db =>            {                var taskIds = new List<int>() { Data2.FinishedTask_1, Data2.FinishedTask_2 }.ToArray();                for (int i = 0; i < taskIds.Length; i++)                {                    //判断当前工位是否有完成任务                    if (taskIds[i] == 0) continue;                    //获取当前工位的目标地址                    var ELine = i == 0 ? Data.ELine_1.ToString() : Data.ELine_2.ToString();                    task = db.Default.Set<WCS_TASK>().Single(v => taskIds[i] == v.ID);                    if (task.STATUS != TaskStatus.堆垛机执行 && task.STATUS != TaskStatus.堆垛机完成) continue;                    if (task.STATUS == TaskStatus.堆垛机完成)                    {                        if (i == 0) Data.FinishedACK_1 = 1;                        else Data.FinishedACK_2 = 1;                        throw new DoException("二次处理堆垛机完成任务");                    }                    if (task.TYPE == TaskType.入库)                    {                        task.ENDTIME = DateTime.Now;                        task.STATUS = TaskStatus.已完成;                        task.UPDATETIME = DateTime.Now;                        db.Default.SaveChanges();                    }                    else if (task.TYPE == TaskType.出库)                    {                        task.STATUS = TaskStatus.堆垛机完成;                        task.UPDATETIME = DateTime.Now;                        db.Default.SaveChanges();                        Uploader.Upload(db);                    }                    else if (task.TYPE == TaskType.移库)                    {                        if (task.STATUS == TaskStatus.堆垛机执行)                        {                            task.STATUS = TaskStatus.已完成;                            task.UPDATETIME = DateTime.Now;                            db.Default.SaveChanges();                            Uploader.Upload(db);                        }                    }                    else throw new Exception($"[{Entity.CODE}]任务类型错误");                    task.CreateStatusLog(db, $"状态由[{TaskStatus.堆垛机执行}]变更为[{task.STATUS}]", this.GetType());                }            });            DB.Do(db =>            {                var taskIds = new List<int>() { Data2.FinishedTask_1, Data2.FinishedTask_2 }.ToArray();                for (int i = 0; i < taskIds.Length; i++)                {                    //判断当前工位是否有完成任务                    if (taskIds[i] == 0) continue;                    //获取当前工位的目标地址                    var ELine = i == 0 ? Data.ELine_1.ToString() : Data.ELine_2.ToString();                    task = db.Default.Set<WCS_TASK>().Single(v => taskIds[i] == v.ID);                    if (task.TYPE == TaskType.入库 && task.STATUS == TaskStatus.已完成)                    {                        if (i == 0) Data.FinishedACK_1 = 1;                        else Data.FinishedACK_2 = 1;                    }                    else if (task.TYPE == TaskType.出库 && task.STATUS == TaskStatus.堆垛机完成)                    {                        var target = Device.Find(ELine).Create<StationDevice>();                        target.Data.Tasknum = task.ID;                        target.Data.Goodsstart = ELine.ToShort();                        target.Data.Goodsend = task.ADDRNEXT.ToShort();                        if (i == 0) Data.FinishedACK_1 = 1;                        else Data.FinishedACK_2 = 1;                    }                    else if (task.TYPE == TaskType.移库 && task.STATUS == TaskStatus.堆垛机完成)                    {                        if (i == 0) Data.FinishedACK_1 = 1;                        else Data.FinishedACK_2 = 1;                    }                    else throw new Exception($"[{Entity.CODE}]任务类型错误");                    task.CreateStatusLog(db, $"状态由[{TaskStatus.堆垛机执行}]变更为[{task.STATUS}]", this.GetType());                }            });        }        /// <summary>        /// 执行堆垛机任务 单例锁        /// </summary>        /// <param name="act"></param>        public void EX(Action<SRMDevice> act)        {            try            {                if (ExDevice.Any(v => v == Entity.CODE)) throw new WarnException($"[{Entity.CODE}]--触发并发管控");                OperateExDevice(Entity.CODE);                act(this);            }            catch (DoException ex)            {                ex.DoExceptionEX(Entity);            }            catch (WarnException ex)            {                ex.WarnExceptionEX(Entity);            }            catch (Exception ex)            {                ex.ExceptionEx(Entity);            }            finally            {                OperateExDevice(Entity.CODE);            }        }        /// <summary>        /// 执行出库任务 出库单例锁        /// </summary>        /// <param name="act"></param>        public void EXOutStock(Action<SRMDevice> act)        {            try            {                var code = "";                if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4")                {                    code = "SRM3-SRM4-Out";                    if (ExDevice.Any(v => v == code)) throw new WarnException($"触发出库并发管控--[{code}]");                    OperateExDevice(code);                }                if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6")                {                    code = "SRM5-SRM6-Out";                    if (ExDevice.Any(v => v == code)) throw new WarnException($"触发出库并发管控--[{code}]");                    OperateExDevice(code);                }                if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8")                {                    code = "SRM7-SRM8-Out";                    if (ExDevice.Any(v => v == code)) throw new WarnException($"触发出库并发管控--[{code}]");                    OperateExDevice(code);                }                act(this);            }            finally            {                if (Entity.CODE == "SRM3" || Entity.CODE == "SRM4") OperateExDevice("SRM3-SRM4-Out");                if (Entity.CODE == "SRM5" || Entity.CODE == "SRM6") OperateExDevice("SRM5-SRM6-Out");                if (Entity.CODE == "SRM7" || Entity.CODE == "SRM8") OperateExDevice("SRM7-SRM8-Out");            }        }        /// <summary>        /// 一工位写任务        /// </summary>        /// <param name="task"></param>        public void WriteTask1(Task task)        {            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]1工位-开始:[{Data.TaskID_1}][{Data.SLine_1}][{Data.SCol_1}][{Data.SLayer_1}][{Data.ELine_1}][{Data.VoucherNo_1}]");            Data.TaskID_1 = task.ID;            Data.SLine_1 = task.Line;            Data.SCol_1 = task.Col;            Data.SLayer_1 = task.Layer;            Data.ELine_1 = task.SRMSTATION.ToShort();            Data.ECol_1 = 0;            Data.ELayer_1 = 0;            Data.VoucherNo_1++;            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]1工位-结束:[{Data.TaskID_1}][{Data.SLine_1}][{Data.SCol_1}][{Data.SLayer_1}][{Data.ELine_1}][{Data.VoucherNo_1}]");        }        /// <summary>        /// 二工位写任务        /// </summary>        /// <param name="task"></param>        public void WriteTask2(Task task)        {            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]2工位-开始:[{Data.TaskID_2}][{Data.SLine_2}][{Data.SCol_2}][{Data.SLayer_2}][{Data.ELine_2}][{Data.VoucherNo_2}]");            Data.TaskID_2 = task.ID;            Data.SLine_2 = task.Line;            Data.SCol_2 = task.Col;            Data.SLayer_2 = task.Layer;            Data.ELine_2 = task.SRMSTATION.ToShort();            Data.ECol_2 = 0;            Data.ELayer_2 = 0;            Data.VoucherNo_2++;            InfoLog.INFO_SRMINFO($"写入堆垛机[{Entity.CODE}]2工位-结束:[{Data.TaskID_2}][{Data.SLine_2}][{Data.SCol_2}][{Data.SLayer_2}][{Data.ELine_2}][{Data.VoucherNo_2}]");        }        /// <summary>        /// 获取任务对应的货叉        /// </summary>        /// <param name="task">任务信息</param>        /// <param name="index">任务在下发任务集合中的索引</param>        /// <returns></returns>        public SrmFork GetFork(Task task, int index)        {            short maxCol = (short)(Entity.CODE == "SRM1" ? 112 : 102);            short min = 1;            if (index > 1) throw new WarnException("一次最多下发两个任务");            //如果索引是1,直接返回货叉2            if (index == 1) return SrmFork.货叉2;            //判断任务列是多少            return task.Col switch            {                102 => Entity.CODE switch                {                    "SRM1" => SrmFork.货叉1,                    _ => SrmFork.货叉2,                },                112 => SrmFork.货叉2,                _ => SrmFork.货叉1,            };        }        /// <summary>        /// 检查同组堆垛机是否有出库任务正在执行        /// </summary>        public void CheckOutTask()        {            //检查同组堆垛机是否有正在执行出库任务的            DB.Do(db =>            {                switch (Entity.CODE)                {                    case "SRM3":                        if (db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM4" && v.TYPE == TaskType.出库))                            throw new DoException("SRM4正在执行出库任务");                        break;                    case "SRM4":                        if (db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM3" && v.TYPE == TaskType.出库))                            throw new DoException("SRM3正在执行出库任务");                        break;                    case "SRM5":                        if (db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM6" && v.TYPE == TaskType.出库))                            throw new DoException("SRM6正在执行出库任务");                        break;                    case "SRM6":                        if (db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM5" && v.TYPE == TaskType.出库))                            throw new DoException("SRM5正在执行出库任务");                        break;                    case "SRM7":                        if (db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM7" && v.TYPE == TaskType.出库))                            throw new DoException("SRM7正在执行出库任务");                        break;                    case "SRM8":                        if (db.Default.Set<WCS_TASK>().Any(v => v.STATUS == TaskStatus.堆垛机执行 && v.DEVICE == "SRM8" && v.TYPE == TaskType.出库))                            throw new DoException("SRM8正在执行出库任务");                        break;                }            });        }    }    /// <summary>    /// 异常处理    /// </summary>    public static class DevEX    {        /// <summary>        /// 计算两点距离        /// </summary>        /// <param name="start">起始点</param>        /// <param name="end">结束点</param>        /// <param name="total">总长</param>        /// <returns></returns>        public static float Distance(float start, float end, float total)        {            float distance = 0;            if (start > end) distance = (total - start) + end;            else distance = end - start;            return distance;        }        public static void DoExceptionEX(this DoException ex, WCS_DEVICE Entity)        {            InfoLog.INFO_INFO($"[{Entity.CODE}]--{ex.Message}");        }        /// <summary>        /// 警报执行记录        /// </summary>        /// <param name="ex">警报信息</param>        /// <param name="Entity">发生设备</param>        /// <param name="reportMonitor">是否上报监控</param>        /// <exception cref="Exception"></exception>        public static void WarnExceptionEX(this WarnException ex, WCS_DEVICE Entity, bool reportMonitor = true)        {            InfoLog.INFO_WARN($"[{Entity.CODE}]--{ex.Message}");            if (ex.Message.Contains("The database operation was expected")) return;            LogHelper.AddWCS_EXCEPTION(ex.Message, Entity.CODE, WCS_EXCEPTIONTYPE.无.ToString());            //排除部分频繁触发的异常上报            if (ex.Message.Contains("触发并发管控")) return;            if (reportMonitor)            {                Ltc.Log(ex.GetBaseException().Message);                throw new Exception($"[{Entity.CODE}]--{ex.Message}");            }        }        public static void ExceptionEx(this Exception ex, WCS_DEVICE Entity)        {            InfoLog.INFO_ERROR($"[{Entity.CODE}]--{ex.Message}");            //排除部分频繁触发的异常上报            if (ex.Message.Contains("Collection was modified; enumeration operation may not execute.")) return;            Ltc.Log(ex.GetBaseException().Message);        }    }    /// <summary>    /// 堆垛机货叉/工位    /// </summary>    public enum SrmFork    {        货叉1 = 0,        货叉2 = 1,    }    /// <summary>    /// 站台位置信息    /// </summary>    public class StationLocation    {        /// <summary>        /// 所有环穿站台的信息        /// </summary>        public static List<StationLocation> ALLlocations { get; set; } = new List<StationLocation>();        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("G1",486326,"RGV3",1567770),                new StationLocation("G2",693631,"RGV3",1567770),                new StationLocation("G3",789931,"RGV3",1567770),                new StationLocation("G4",961595,"RGV3",1567770),                new StationLocation("G5",1013350,"RGV3",1567770),                new StationLocation("G6",1069938,"RGV3",1567770),                new StationLocation("G7",1126338,"RGV3",1567770),                new StationLocation("G8",1178355,"RGV3",1567770),                new StationLocation("G9",1256875,"RGV3",1567770),                new StationLocation("G10",1313239,"RGV3",1567770),                new StationLocation("G11",1369970,"RGV3",1567770),            });        }        public StationLocation(string station, int location, string plc, int length)        {            Station = station;            Location = location;            PLC = plc;            Length = length;        }        /// <summary>        /// 输送机设备组编号        /// </summary>        public string Station { get; set; }        /// <summary>        /// 输送机在环轨中的位置        /// </summary>        public int Location { get; set; }        /// <summary>        /// 所属RGV组 PLC名称        /// </summary>        public string PLC { get; set; }        /// <summary>        /// 所属环穿轨道的长度        /// </summary>        public int Length { get; set; }    }    /// <summary>    /// 巷道信息    /// </summary>    public class TunnelInfo    {        public WCS_DEVICE Tunnel;        public WCS_DEVICE taskIN;        public Device<ISRM520, ISRM521, ISRM537> SRM;    }}
 |