zxx
2025-05-31 267ffc1263e9975adf0d3dcca9ccc5d7dbd239f6
HH.WCS.Mobox3/HH.WCS.Mobox3.JuShi/process/TaskProcess.cs
@@ -20,6 +20,13 @@
using Opc.Ua;
using System.Collections;
using System.Xml.Linq;
using System.Threading;
using static HH.WCS.JuShi.dispatch.NDC;
using static HH.WCS.JuShi.util.Settings;
using System.ComponentModel;
using Newtonsoft.Json.Linq;
using S7.Net;
using System.Threading.Tasks;
namespace HH.WCS.JuShi.process
{
@@ -99,17 +106,129 @@
        /// <param name="state"></param>
        internal static void OperateStatus(WCSTask mst, int state)
        {
            if (state == 4)
            if (state == 4)//取货完成
            {
                CacheBitUpdate(mst, true);
                //拆托机安全交互
                //ctjSafe(mst);
            }
            if (state == 6)//卸货完成
            {
                CacheBitUpdate(mst, false);
                ////rgv安全交互
                //rgvSafe(mst);
                ////拆托机安全交互
                //ctjSafe(mst);
            }
            if (state == 7)
            {
                CacheBitCancelUpdate(mst);
            }
        }
        //rgv安全交互
        private static void rgvSafe(WCSTask mst)
        {
            //rgv安全交互  根据终点货位找到是哪个rgv
            var reservoir = Settings.ReservoirAreas.Where(a => a.areaName == "立库入库区").FirstOrDefault();
            if (mst.S_END_AREA.Equals(reservoir.areaCode))
            {
                var safeInteractions = Settings.SafeInteractions.Where(a => a.location == mst.S_END_LOC).FirstOrDefault();
                var rgvSafeInteraction = DeviceProcess.rgvSafeInteraction;
                //处理信号
                var startsub = safeInteractions.code;
                var res = rgvSafeInteraction.Substring((startsub - 1) * 2 + 1, 1);
                //var safelists = JsonConvert.DeserializeObject<List<SafeInteraction>>(DeviceProcess.rgvSafeInteraction);
                LogHelper.Info($"RGV安全交互缓存信号{rgvSafeInteraction}");
                //不等于 2卸货完成确认信号 就接着发
                if (res != "2")
                {
                    string datastr = "3f001020304050600d0a";
                    string a = ((startsub - 1) * 2).ToString();
                    //返回信号处理
                    datastr = datastr.Replace(a + "0", a + "1");
                    LogHelper.Info($"RGV安全交互发送信号{safeInteractions.ip},{datastr}");
                    PlcHelper.SendHex(safeInteractions.ip, datastr);
                    //休眠3秒再调
                    Thread.Sleep(3000);
                    rgvSafe(mst);
                }
                else
                {
                    //休眠10秒再发信号 (给现场设备吸合时间说是)
                    Thread.Sleep(10000);
                    LogHelper.Info($"RGV安全交互发送信号{safeInteractions.ip},3f001020304050600d0a");
                    //无状态信号
                    PlcHelper.SendHex(safeInteractions.ip, "3f001020304050600d0a");
                }
            }
        }
        //拆托机安全交互
        private static void ctjSafe(WCSTask mst)
        {
            PlcDeviceTable plcDeviceTable = S7Helper.plcDeviceTables;
            string deviceno = null;//线体
            //找到线体 根据线体找内存里的状态
            var rkreservoirs = Settings.ConveyorLinesInfos.Where(s => s.location == mst.S_END_LOC).FirstOrDefault();
            var ckreservoirs = Settings.ConveyorLinesInfos.Where(s => s.location == mst.S_START_LOC).FirstOrDefault();
            //入口
            if (rkreservoirs != null)
            {
                if (rkreservoirs.deviceNo == "1")
                {
                    deviceno = "1";
                }
                else if (rkreservoirs.deviceNo == "2")
                {
                    deviceno = "4";
                }
            }
            //出口
            else if (ckreservoirs != null)
            {
                if (ckreservoirs.deviceNo == "1")
                {
                    deviceno = "3";
                }
                else if (rkreservoirs.deviceNo == "2")
                {
                    deviceno = "6";
                }
            }
            LogHelper.Info($"拆托机安全交互写入参数{deviceno},{JsonConvert.SerializeObject(plcDeviceTable)}");
            if (plcDeviceTable != null && deviceno != null)
            {
                //var plcDeviceTables = S7Helper.plcDeviceTables.Where(s => s.DeviceNo == plcDeviceTable.DeviceNo);
                //s7写入
                int addr = 182;         //偏移量
                int offsetAddr = 0;         //偏移量
                string deviceNo = null;//拆托机号
                if (deviceno == "3")
                {
                    offsetAddr = 1;
                    deviceNo = "1";
                }
                else if (deviceno == "6")
                {
                    offsetAddr = 3;
                    deviceNo = "2";
                }
                else if (deviceno == "1")
                {
                    offsetAddr = 0;
                    deviceNo = "1";
                }
                else if (deviceno == "4")
                {
                    offsetAddr = 2;
                    deviceNo = "2";
                }
                LogHelper.Info($"拆托机安全交互写入{deviceNo},{addr}");
                S7Helper.WriteDouble(deviceNo, 9, addr, offsetAddr, 1);
            }
        }
@@ -316,70 +435,45 @@
                    string parmeD = "}";
                    string parme = parmeS + src + dst + parmeD;
                    int res = 0;
                    if (mst.S_TYPE == "呼叫空托" || mst.S_TYPE == "按钮盒调用空托" || mst.S_TYPE == "拆托")
                    {
                        PlcDeviceTable plcDeviceTable = null;
                        //找到线体 根据线体找内存里的状态
                        var reservoirs1 = Settings.ConveyorLinesInfos.Where(s => s.location == startLoc.S_CODE).FirstOrDefault();
                        plcDeviceTable = S7Helper.plcDeviceTables.Find(a => a.DeviceNo == reservoirs1.code);
                        if (plcDeviceTable != null)
                        {
                            if (mst.S_TYPE == "呼叫空托" || mst.S_TYPE == "按钮盒调用空托")
                            {
                                LogHelper.Info($"呼叫空托状态参数{JsonConvert.SerializeObject(plcDeviceTable)}", "任务");
                                //0-脱机状态,1-待机状态,2-运行中    待机且有托盘且请求取框才走
                                if (plcDeviceTable.workMode == 1 && plcDeviceTable.lightAction == 1 && plcDeviceTable.requestTake)
                                {
                                    LogHelper.Info($"推送任务参数{parme}", "任务");
                                    res = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, parme);
                                }
                            }
                            else if (mst.S_TYPE == "拆托")
                            {
                                LogHelper.Info($"拆托状态参数{JsonConvert.SerializeObject(plcDeviceTable)}", "任务");
                                //0-脱机状态,1-待机状态,2-运行中    待机且无托盘且允许放框才走
                                if (plcDeviceTable.workMode == 1 && plcDeviceTable.lightAction == 0 && plcDeviceTable.requestPut)
                                {
                                    LogHelper.Info($"推送任务参数{parme}", "任务");
                                    res = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, parme);
                                }
                            }
                            //任务完成写入s7
                            if (res > 0)
                            {
                                //s7写入 agv取框完成
                                double addr = 0;         //偏移量
                                string deviceNo = null;//拆托机号
                                if (plcDeviceTable.DeviceNo == 1003)
                                {
                                    addr = 90.1;
                                    deviceNo = "1";
                                }
                                else if (plcDeviceTable.DeviceNo == 1006)
                                {
                                    addr = 180.1;
                                    deviceNo = "2";
                                }
                                else if (plcDeviceTable.DeviceNo == 1001)
                                {
                                    addr = 30.0;
                                    deviceNo = "1";
                                }
                                else if (plcDeviceTable.DeviceNo == 1004)
                                {
                                    addr = 120.0;
                                    deviceNo = "2";
                                }
                                S7Helper.WriteDouble(deviceNo, 9, addr, 1);
                            }
                        }
                    }
                    else
                    {
                        LogHelper.Info($"推送任务参数{parme}", "任务");
                        res = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, parme);
                    }
                    LogHelper.Info($"推送任务参数{parme}", "任务");
                    res = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, parme);
                    #region
                    //if (mst.S_TYPE == "呼叫空托" || mst.S_TYPE == "按钮盒调用空托" || mst.S_TYPE == "拆托")
                    //{
                    //    PlcDeviceTable plcDeviceTable = null;
                    //    //找到线体 根据线体找内存里的状态
                    //    var reservoirs1 = Settings.ConveyorLinesInfos.Where(s => s.location == startLoc.S_CODE).FirstOrDefault();
                    //    plcDeviceTable = S7Helper.plcDeviceTables.Find(a => a.DeviceNo == reservoirs1.code);
                    //    if (plcDeviceTable != null)
                    //    {
                    //        if (mst.S_TYPE == "呼叫空托" || mst.S_TYPE == "按钮盒调用空托")
                    //        {
                    //            LogHelper.Info($"呼叫空托状态参数{JsonConvert.SerializeObject(plcDeviceTable)}", "任务");
                    //            //0-脱机状态,1-待机状态,2-运行中    待机且有托盘且请求取框才走
                    //            if (plcDeviceTable.workMode == 1 && plcDeviceTable.lightAction == 1 && plcDeviceTable.requestTake)
                    //            {
                    //                LogHelper.Info($"推送任务参数{parme}", "任务");
                    //                res = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, parme);
                    //            }
                    //        }
                    //        else if (mst.S_TYPE == "拆托")
                    //        {
                    //            LogHelper.Info($"拆托状态参数{JsonConvert.SerializeObject(plcDeviceTable)}", "任务");
                    //            //0-脱机状态,1-待机状态,2-运行中    待机且无托盘且允许放框才走
                    //            if (plcDeviceTable.workMode == 1 && plcDeviceTable.lightAction == 0 && plcDeviceTable.requestPut)
                    //            {
                    //                LogHelper.Info($"推送任务参数{parme}", "任务");
                    //                res = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, parme);
                    //            }
                    //        }
                    //    }
                    //}
                    //else
                    //{
                    //    LogHelper.Info($"推送任务参数{parme}", "任务");
                    //    res = GZRobot.CreateOrder(mst.S_CODE, mst.N_PRIORITY, parme);
                    //}
                    #endregion
                    if (res > 0)
                    {
                        //更新任务状态
@@ -730,6 +824,52 @@
                    {
                        list.RemoveAll(s => loca.Contains(s.S_CODE));
                    }
                    // 3. 如果是立库入库区,检查 PLC 是否允许卸载
                    var reservoirs = Settings.ReservoirAreas.FirstOrDefault(s => s.areaName == "立库入库区");
                    if (reservoirs != null && reservoirs.areaCode.Equals(area))
                    {
                        var plcDeviceTable = S7Helper.plcDeviceTables;
                        // 先收集要移除的货位,避免在遍历时修改集合
                        List<Location> locationsToRemove = new List<Location>();
                        foreach (var location in list)
                        {
                            var safeInteraction = Settings.SafeInteractions.FirstOrDefault(s => s.location == location.S_CODE);
                            if (safeInteraction != null)
                            {
                                // 检查 PLC 是否允许卸载(取第二位数字,判断是否为 1)
                                string allowUnloadStr = plcDeviceTable.RGVAllowUnload[safeInteraction.code].ToString();
                                int allowUnload = int.Parse(allowUnloadStr.Substring(1, 1));
                                if (allowUnload != 1)
                                {
                                    locationsToRemove.Add(location); // 不允许卸载,加入待移除列表
                                }
                            }
                        }
                        // 遍历结束后,再统一移除不符合条件的货位
                        foreach (var locToRemove in locationsToRemove)
                        {
                            list.Remove(locToRemove);
                        }
                    }
                    ////过滤一下 允许进入的才分配
                    //var reservoirs = Settings.ReservoirAreas.Where(s => s.areaName == "立库入库区").FirstOrDefault();
                    //if (reservoirs.areaCode.Equals(area))
                    //{
                    //    var plcDeviceTable = S7Helper.plcDeviceTables;
                    //    foreach (var l in list)
                    //    {
                    //        var safeInteraction = Settings.SafeInteractions.Where(s => s.location == l.S_CODE).FirstOrDefault();
                    //        var res = int.Parse(plcDeviceTable.RGVAllowUnload[safeInteraction.code].ToString().Substring(1, 1));
                    //        if (res!=1)
                    //        {
                    //            list.Remove(l);
                    //        }
                    //    }
                    //}
                    //符合条件的排序选第一个  先找第一个
                    if (list.Count > 0)
@@ -1263,12 +1403,11 @@
            try
            {
                var db = new SqlHelper<object>().GetInstance();
                //三表联查查出有该物料的货位编号
                //两表联查查出有该物料的货位编号  (现场没有物料表)
                var locCntrs = db.Queryable<LocCntrRel>().LeftJoin<CntrItemDetail>((p, m) => p.S_CNTR_CODE == m.S_CNTR_CODE)
                .LeftJoin<TN_Material>((p, m, s) => m.S_ITEM_CODE == s.S_ITEM_CODE)
                .Where((p, m, s) => s.S_ITEM_CODE == itemCode)
                .OrderBy((p, m, s) => p.T_CREATE)  //按创建时间顺序
                .Select((p, m, s) => p.S_LOC_CODE) // 选择托盘物料表的数据
                .Where((p, m) => m.S_ITEM_CODE == itemCode)
                .OrderBy((p, m) => p.T_CREATE)  //按创建时间顺序
                .Select((p, m) => p.S_LOC_CODE) // 选择托盘物料表的数据
                .ToList();
                LogHelper.Info($"有物料{itemCode}的货位编号{JsonConvert.SerializeObject(locCntrs)}");
                //找常规送检区内含有查出物料货位的货位
@@ -1302,7 +1441,7 @@
        internal static Results UpdateFullStatus(List<CameraMonitor> models)
        {
            var result = new Results() { Code = "0", Message = "操作成功", Data = null };
            var db = new SqlHelper<Location>().GetInstance();
            var db = new SqlHelper<object>().GetInstance();
            //校验与内存是否一致
            if (monitorStatus != null)
            {
@@ -1388,40 +1527,50 @@
        //摄像头监测空托缓存区
        private static void ProcessEmptyTrayAreas(SqlSugar.ISqlSugarClient db, Location loc, string areaCode1, string areaCode2)
        {
            var plcDeviceTable = new PlcDeviceTable();
            string endLoc = null;
            if (loc.S_AREA_CODE.Equals(areaCode1))
            var plcDeviceTable = S7Helper.plcDeviceTables;
            if (plcDeviceTable != null)
            {
                plcDeviceTable = S7Helper.plcDeviceTables.Find(s => s.DeviceNo == 1001);
                endLoc = Settings.linePlcInfos.Where(s => s.code == "拆托机1").FirstOrDefault().inLoca;
            }
            else if (loc.S_AREA_CODE.Equals(areaCode2))//六寸空托
            {
                plcDeviceTable = S7Helper.plcDeviceTables.Find(s => s.DeviceNo == 1004);
                endLoc = Settings.linePlcInfos.Where(s => s.code == "拆托机2").FirstOrDefault().inLoca;
            }
            //判断是否允许放框
            if (plcDeviceTable.workMode == 1 && plcDeviceTable.lightAction == 0 && plcDeviceTable.requestPut)
            {
                //创建任务 从空托缓存区叉个料到拆托机
                var list = db.Queryable<Location>().Where(a => a.S_AREA_CODE.Trim() == loc.S_AREA_CODE
                && a.N_CURRENT_NUM > 0 && a.N_LOCK_STATE == 0).OrderByDescending(a => a.N_ROW)
                .OrderByDescending(a => a.N_COL).First();
                var startLoc = list.S_CODE;
                string trayCode = ContainerHelper.GenerateCntrNo();
                LogHelper.Info($"创建任务 起点:{startLoc}终点:{endLoc}", "拆托");
                var res = TaskProcess.CreateTransport(startLoc, endLoc, "拆托", trayCode, 1, 1);
                if (res)
                string endLoc = null;
                bool request = false;
                if (loc.S_AREA_CODE.Equals(areaCode1))
                {
                    LogHelper.Info($"起点:{startLoc}终点:{endLoc}任务创建成功", "拆托");
                    request = plcDeviceTable.requestPut1;
                    endLoc = Settings.linePlcInfos.Where(s => s.code == "拆托机1").FirstOrDefault().inLoca;
                }
                else
                else if (loc.S_AREA_CODE.Equals(areaCode2))//六寸空托
                {
                    LogHelper.Info($"起点:{startLoc}终点:{endLoc}任务创建失败", "拆托");
                    request = plcDeviceTable.requestPut2;
                    endLoc = Settings.linePlcInfos.Where(s => s.code == "拆托机2").FirstOrDefault().inLoca;
                }
                //判断是否允许放框
                if (request)
                {
                    //创建任务 从空托缓存区到拆托机
                    var list = db.Queryable<Location>().Where(a => a.S_AREA_CODE.Trim() == loc.S_AREA_CODE
                    && a.N_CURRENT_NUM > 0 && a.N_LOCK_STATE == 0).OrderByDescending(a => a.N_ROW)
                    .OrderByDescending(a => a.N_COL).First();
                    var startLoc = list.S_CODE;
                    string trayCode = ContainerHelper.GenerateCntrNo();
                    LogHelper.Info($"创建任务 起点:{startLoc}终点:{endLoc}", "拆托");
                    var res = TaskProcess.CreateTransport(startLoc, endLoc, "拆托", trayCode, 1, 1);
                    if (res)
                    {
                        LogHelper.Info($"起点:{startLoc}终点:{endLoc}任务创建成功", "拆托");
                    }
                    else
                    {
                        LogHelper.Info($"起点:{startLoc}终点:{endLoc}任务创建失败", "拆托");
                    }
                }
            }
            else
            {
                LogHelper.Info($"未读取到拆托机信号", "拆托");
            }
        }
        /// <summary>
        /// 抽检主动呼叫    起点:送检缓存区
@@ -1438,7 +1587,7 @@
                //根据物料找某库区的货位
                var cgreservoirs = Settings.ReservoirAreas.Where(s => s.areaName == "送检缓存区").FirstOrDefault();
                var startloc = getLocByMaterial(model.S_ITEM_CODE, cgreservoirs.areaCode);
                if (startloc==null)
                if (startloc == null)
                {
                    return new Results { Code = "1", Message = $"未找到包含物料{model.S_ITEM_CODE}的货位", Data = null };
                }
@@ -1467,7 +1616,86 @@
                throw;
            }
        }
        /// <summary>
        /// 主动物料绑定
        /// </summary>
        /// <param name="model.S_ITEM_CODE">物料编码(选填)</param>
        /// <param name="model.BIND_LOC">绑定货位</param>
        /// <returns></returns>
        internal static Results bindMaterial(GetSubmitCheck model)
        {
            var result = new Results() { Code = "0", Message = "物料绑定成功!", Data = null };
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                var loc = db.Queryable<Location>().Where(a => a.S_CODE == model.BIND_LOC).First();
                if (loc == null || loc.N_LOCK_STATE != 0)
                {
                    return new Results { Code = "1", Message = $"绑定货位不存在或已被锁", Data = null };
                }
                string cntrStr = ContainerHelper.GenerateCntrNo();
                var locCntrRel = db.Queryable<LocCntrRel>().Where(a => a.S_LOC_CODE == model.BIND_LOC).First();
                if (locCntrRel != null)
                {
                    cntrStr = locCntrRel.S_CNTR_CODE;
                }
                var res = ContainerHelper.BindLocCntrs(model.BIND_LOC, cntrStr, model.S_ITEM_CODE, "布卷");
                if (!res)
                {
                    return new Results { Code = "1", Message = $"物料{model.S_ITEM_CODE}货位{model.BIND_LOC}绑定失败", Data = null };
                }
                loc.N_CURRENT_NUM++;
                var res2 = db.Updateable(loc).UpdateColumns(it => it.N_CURRENT_NUM).ExecuteCommand() > 0;
                if (!res2)
                {
                    return new Results { Code = "1", Message = $"货位{model.BIND_LOC}当前数量自增失败", Data = null };
                }
                return result;
            }
            catch (Exception ex)
            {
                Console.WriteLine("bindMaterial:" + ex.Message + ex.StackTrace);
                LogHelper.Error("bindMaterial:" + ex.Message, ex);
                throw;
            }
        }
        /// <summary>
        /// 整排物料绑定
        /// </summary>
        /// <param name="bondLoc">绑定货位</param>
        /// <returns></returns>
        internal static Results multBindMaterial(string bondLoc)
        {
            var result = new Results() { Code = "0", Message = "整排物料绑定成功!", Data = null };
            var db = new SqlHelper<object>().GetInstance();
            try
            {
                var location = db.Queryable<Location>().Where(a => a.S_CODE == bondLoc).First();
                //查出这一排的货位
                var loclist = db.Queryable<Location>()
                    .Where(a => a.S_AREA_CODE == location.S_AREA_CODE && a.N_ROW == location.N_ROW).ToList();
                foreach (var loc in loclist)
                {
                    //没锁的且没货的才绑
                    if (loc.N_LOCK_STATE == 0 && loc.N_CURRENT_NUM < loc.N_CAPACITY)
                    {
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("multBindMaterial:" + ex.Message + ex.StackTrace);
                LogHelper.Error("multBindMaterial:" + ex.Message, ex);
                throw;
            }
            return result;
        }
        /// <summary>
        /// 按钮盒调用下线
        /// </summary>
@@ -1570,40 +1798,122 @@
        {
            //0允许进入 1不允许进入
            var result = new safeResult() { code = "1", msg = "success" };
            var db = new SqlHelper<Location>().GetInstance();
            try
            {
                var reservoirs = Settings.SafeDoors.Where(s => s.pointCode == model.STATION_NAME).FirstOrDefault();//y0-0000 y1-0001  on-FF00  off-0000
                TcpClient tcpClient = new TcpClient();
                //请求进入
                if (model.APPLY_CODE.Equals("1") || model.APPLY_CODE.Equals("5"))
                var reservoirs = Settings.SafeInteractions.Where(s => s.location == model.STATION_NAME).FirstOrDefault();//y0-0000 y1-0001  on-FF00  off-0000
                //var rgvSafeInteraction = DeviceProcess.rgvSafeInteraction;
                var plcDeviceTable = S7Helper.plcDeviceTables;
                if (plcDeviceTable != null)
                {
                    //发送信号写请求开门
                    var str = tcpClient.WriteSingleRegisterRtu("01050000FF008C3A", reservoirs.ip, int.Parse(reservoirs.port));
                    //发送信号读门状态
                    var x0bool = tcpClient.ReadInputRegistersRtu("010200000001B9CA", reservoirs.ip, int.Parse(reservoirs.port));
                    //如果开门到位
                    if (x0bool)
                    //RGV
                    if (reservoirs.type.Equals("RGV"))
                    {
                        return new safeResult() { code = "0", msg = "success" };
                    }
                }
                //请求离开
                else if (model.APPLY_CODE.Equals("4") || model.APPLY_CODE.Equals("8"))
                {
                    //发送信号写请求关门
                    var str = tcpClient.WriteSingleRegisterRtu("010500000000CDCA", reservoirs.ip, int.Parse(reservoirs.port));
                    var str2 = tcpClient.WriteSingleRegisterRtu("01050001FF00DDFA", reservoirs.ip, int.Parse(reservoirs.port));
                    //发送信号读门状态
                    var x0bool = tcpClient.ReadInputRegistersRtu("010200010001E80A", reservoirs.ip, int.Parse(reservoirs.port));
                    //如果门已关
                    if (x0bool)
                    {
                        return new safeResult() { code = "0", msg = "success" };
                    }
                        LogHelper.Info($"RGV安全交互  请求点位:{model.STATION_NAME}请求码:{model.APPLY_CODE}");
                        //处理信号
                        var res = int.Parse(plcDeviceTable.RGVAllowUnload[reservoirs.code].ToString().Substring(1, 1));
                        //根据ip读状态
                        LogHelper.Info($"RGV安全交互缓存信号{res},{JsonConvert.SerializeObject(plcDeviceTable.RGVAllowUnload)}");
                        //卸货请求进入
                        if (model.APPLY_CODE.Equals("5"))
                        {
                            //1允许卸货
                            if (res == 1)
                            {
                                LogHelper.Info($"RGV安全交互 允许卸货");
                                return new safeResult() { code = "0", msg = "success" };
                            }
                        }
                        //卸货后已离开
                        else if (model.APPLY_CODE.Equals("8"))
                        {
                            //发送卸货完成、复位信号
                            //卸货完成信号
                            S7Helper.WriteInt(50, reservoirs.code * 2 - 2, (short)(reservoirs.code * 10 + 1));
                            // 启动后台任务处理延迟复位
                            Task.Run(async () =>
                            {
                                //10秒后复位
                                await Task.Delay(10000);
                                S7Helper.WriteInt(50, reservoirs.code * 2 - 2, (short)(reservoirs.code * 10));
                                LogHelper.Info($"RGV安全交互 复位完成");
                            });
                            //10秒后复位
                            //S7Helper.WriteInt(50, reservoirs.code * 2 - 2, (short)(reservoirs.code * 10));
                            //safeAssistant(reservoirs.code, res);
                            LogHelper.Info($"RGV安全交互 卸货完成");
                            return new safeResult() { code = "0", msg = "success" };
                        }
                    }
                    //拆托机
                    else if (reservoirs.type.Equals("CTJ"))
                    {
                        LogHelper.Info($"拆托机安全交互  请求点位:{model.STATION_NAME}请求码:{model.APPLY_CODE}");
                        //找到线体 根据线体找内存里的状态
                        var reservoirs1 = Settings.ConveyorLinesInfos.Where(s => s.location == model.STATION_NAME).FirstOrDefault();
                        LogHelper.Info($"拆托机安全交互参数{JsonConvert.SerializeObject(plcDeviceTable)}");
                        if (model.APPLY_CODE.Equals("1"))
                        {
                            //0-脱机状态,1-待机状态,2-运行中    待机且有托盘且请求取框才走
                            if ((reservoirs1.deviceNo == "1" && plcDeviceTable.requestTake1) ||
                                (reservoirs1.deviceNo == "2" && plcDeviceTable.requestTake2))
                            {
                                LogHelper.Info($"拆托机安全交互 允许取框");
                                return new safeResult() { code = "0", msg = "success" };
                            }
                        }
                        else if (model.APPLY_CODE.Equals("5"))
                        {
                            //0-脱机状态,1-待机状态,2-运行中    待机且无托盘且允许放框才走
                            if ((reservoirs1.deviceNo == "1" && plcDeviceTable.requestPut1) ||
                                (reservoirs1.deviceNo == "2" && plcDeviceTable.requestPut2))
                            {
                                LogHelper.Info($"拆托机安全交互 允许放框");
                                return new safeResult() { code = "0", msg = "success" };
                            }
                        }
                        //取货离开
                        else if (model.APPLY_CODE.Equals("4"))
                        {
                            int offsetAddr = 8;
                            if (reservoirs1.deviceNo == "1")
                            {
                                offsetAddr = 1;
                            }
                            else if (reservoirs1.deviceNo == "2")
                            {
                                offsetAddr = 3;
                            }
                            LogHelper.Info($"拆托机安全交互写入{reservoirs1.deviceNo},{offsetAddr}");
                            S7Helper.WriteDouble(reservoirs1.deviceNo, 9, 182, offsetAddr, 1);
                            LogHelper.Info($"拆托机安全交互 取框离开");
                            return new safeResult() { code = "0", msg = "success" };
                        }
                        //卸货离开
                        else if (model.APPLY_CODE.Equals("8"))
                        {
                            int offsetAddr = 8;//随便给一个
                            if (reservoirs1.deviceNo == "1")
                            {
                                offsetAddr = 0;
                            }
                            else if (reservoirs1.deviceNo == "2")
                            {
                                offsetAddr = 2;
                            }
                            LogHelper.Info($"拆托机安全交互写入{reservoirs1.deviceNo},{offsetAddr}");
                            S7Helper.WriteDouble(reservoirs1.deviceNo, 9, 182, offsetAddr, 1);
                            LogHelper.Info($"拆托机安全交互 取框离开");
                            return new safeResult() { code = "0", msg = "success" };
                        }
                    }
                }
                return null;
                return result;
            }
            catch (Exception ex)
            {
@@ -1612,6 +1922,63 @@
                throw;
            }
        }
        //循环发送信号
        private static void safeAssistant(int code, int res)
        {
            Thread.Sleep(10000);
            S7Helper.WriteInt(50, code * 2 - 2, (short)(code * 10));
            LogHelper.Info($"RGV安全交互 复位完成");
            ////2卸货完成确认
            //if (res != 2)
            //{
            //    //卸货完成信号
            //    S7Helper.WriteInt(50, code * 2 - 2, (short)(code * 10 + 1));
            //    Thread.Sleep(3000);
            //    safeAssistant(code, res);
            //}
            //else
            //{
            //    S7Helper.WriteInt(50, code * 2 - 2, (short)(code * 10));
            //}
        }
        /// <summary>
        /// 按钮控制服务开关
        /// </summary>
        /// <param name="isusing.S_STATUS">服务状态</param>
        /// <param name="isusing.S_TYPE">服务类型</param>
        /// <returns></returns>
        internal static Results switchButton(Isusing isusing)
        {
            var db = new SqlHelper<object>().GetInstance();
            var result = new Results() { Code = "1", Message = $"服务状态失败!", Data = null };
            var isusinglist = db.Queryable<Isusing>().Where(a => a.S_TYPE == isusing.S_TYPE).First();
            isusinglist.S_STATUS = isusing.S_STATUS;
            var res = db.Updateable(isusinglist).UpdateColumns(it => it.S_STATUS).ExecuteCommand() > 0;
            if (res)
            {
                return new Results() { Code = "0", Message = $"服务状态修改成功!", Data = null };
            }
            return result;
        }
        //tcp发送信号 测试用
        internal static Results tcpSend(string str)
        {
            var reservoirs = Settings.SafeInteractions.Where(s => s.code == 1).FirstOrDefault();
            //测试用
            LogHelper.Info($"RGV安全交互发送信号{reservoirs.ip},{str}");
            //无状态信号
            bool res = PlcHelper.SendHex(reservoirs.ip, str);
            if (res)
            {
                return new Results() { Code = "0", Message = $"发送成功", Data = null };
            }
            return new Results() { Code = "1", Message = $"发送失败", Data = null };
        }
    }
}