|
|
using Khd.Core.Domain.Dto.wcs;
|
|
|
using Khd.Core.Domain.Models;
|
|
|
using Khd.Core.EntityFramework;
|
|
|
using Khd.Core.Wcs.Global;
|
|
|
using Masuit.Tools.Logging;
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
using Microsoft.Extensions.Hosting;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Security.Policy;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
using Thrift.Server;
|
|
|
using Thrift.Transport;
|
|
|
using ThriftService;
|
|
|
using static AngleSharp.Css.Values.CssRadialGradientValue;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Threading.Tasks;
|
|
|
using Thrift.Protocol;
|
|
|
using System.Security.Cryptography.Xml;
|
|
|
using Z.EntityFramework.Plus;
|
|
|
using System.Net.NetworkInformation;
|
|
|
|
|
|
namespace Khd.Core.Wcs.Wcs
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 上件点线程
|
|
|
/// </summary>
|
|
|
public class UpLine : WcsServer
|
|
|
{
|
|
|
private readonly IHost _host;
|
|
|
private readonly Plc.S7.Plc _plc;
|
|
|
List<NodeSetting> ScanPoint { get; set; }//点位信息
|
|
|
BaseSitenode? sitenode { get; set; }//站台信息
|
|
|
|
|
|
NodeSetting? NodeSettingCarNo { get; set; }
|
|
|
NodeSetting? NodeSettingCarState { get; set; }
|
|
|
NodeSetting? NodeSettingCarRun { get; set; }
|
|
|
NodeSetting? NodeSettingWcsState { get; set; }
|
|
|
NodeSetting? NodeSettingWcsSend { get; set; }
|
|
|
NodeSetting? NodeSettingWcsSendMaterial { get; set; }
|
|
|
NodeSetting? NodeSettingPLCSendSendMaterialstate { get; set; }
|
|
|
public UpLine(IHost host, Plc.S7.Plc plc, string siteNo)
|
|
|
{
|
|
|
this._host = host;
|
|
|
this._plc = plc;
|
|
|
//this.ScanPoint = StaticData.NodeSettingList.Where(t => t.siteNo == siteNo).ToList();//加载当前站点所对应的点位
|
|
|
this.sitenode = StaticData.SiteNodeList.FirstOrDefault(t => t.siteNo == siteNo);//获取当前站台信息
|
|
|
this.NodeSettingCarNo = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carno"));
|
|
|
this.NodeSettingCarState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carstate"));
|
|
|
this.NodeSettingCarRun = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("carrun"));
|
|
|
this.NodeSettingWcsState = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendK"));
|
|
|
this.NodeSettingWcsSend = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcsend"));
|
|
|
this.NodeSettingWcsSendMaterial = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("wcssendmessage"));
|
|
|
this.NodeSettingPLCSendSendMaterialstate = this.ScanPoint.FirstOrDefault(t => t.plcpointNo.Contains("plcsendmessage"));
|
|
|
try
|
|
|
{
|
|
|
//默认启动,清理plc的上位机写入点位值
|
|
|
this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei);
|
|
|
this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei);
|
|
|
this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
Console.WriteLine("站点" + siteNo + " 初始化数据异常" + ex.Message);
|
|
|
LogManager.Error(ex);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 启动线程
|
|
|
/// </summary>
|
|
|
public void StartPoint()
|
|
|
{
|
|
|
Thread TestThread1 = new Thread(new ParameterizedThreadStart(StartScanThrift));
|
|
|
TestThread1.IsBackground = true;
|
|
|
TestThread1.Start(this.sitenode);
|
|
|
Thread TestThread2 = new Thread(new ParameterizedThreadStart(StartSendCarThrift));
|
|
|
TestThread2.IsBackground = true;
|
|
|
TestThread2.Start(this.sitenode);
|
|
|
Thread TestThread3 = new Thread(ClearSendCar);
|
|
|
TestThread3.IsBackground = true;
|
|
|
TestThread3.Start();
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 启动推送车辆到位队列
|
|
|
/// </summary>
|
|
|
private void StartScanThrift(object NodeSettingModel)
|
|
|
{
|
|
|
var sitenodemodel = NodeSettingModel as BaseSitenode;
|
|
|
int TSpoint = Convert.ToInt32(sitenodemodel.thriftPort);
|
|
|
string IpAddress = sitenodemodel.siteIpaddress;
|
|
|
TTransport transport = new TSocket(IpAddress, TSpoint);
|
|
|
while (true)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
//启动thrift 推送服务
|
|
|
//推送车辆到位情况
|
|
|
transport.Open();
|
|
|
TProtocol protocol = new TBinaryProtocol(transport);
|
|
|
WcsThrift.Client client = new WcsThrift.Client(protocol);
|
|
|
client.hello(ReceiveCarNo(""));
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
LogManager.Info($"wcs上件控制类推送车辆到位信息Thrift方法报错 >>> {ex.Message}");
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
transport.Close();
|
|
|
Thread.Sleep(1000);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 启动小车扫描监听队列
|
|
|
/// </summary>
|
|
|
private void StartSendCarThrift(object NodeSettingModel)
|
|
|
{
|
|
|
SendCar(null, null, null);
|
|
|
var sitenodemodel = NodeSettingModel as BaseSitenode;
|
|
|
int JSport = Convert.ToInt32(sitenodemodel.siteServerport);
|
|
|
while (true)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
//启动thrift接收服务
|
|
|
//接收挂具与Vin物料信息,上件绑定信息
|
|
|
WcsServer wcsServer = new WcsServer();
|
|
|
wcsServer.SendCarEvent += SendCar;
|
|
|
WcsThrift.Processor processor = new WcsThrift.Processor(wcsServer);
|
|
|
TServerTransport serverTransport = new TServerSocket(JSport);
|
|
|
TServer server = new TSimpleServer(processor, serverTransport);
|
|
|
Console.WriteLine($"站点:{this.sitenode.siteNo},当前时间:{DateTime.Now},接收客户端发车方法启动.. ");
|
|
|
server.Serve();
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
LogManager.Info($"wcs上件控制类控制发车Thrift方法报错 >>> {ex.Message}");
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
Thread.Sleep(1000);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 发车
|
|
|
/// </summary>
|
|
|
/// <param name="carlist"></param>
|
|
|
/// <param name="order_code"></param>
|
|
|
/// <param name="amount"></param>
|
|
|
/// <returns></returns>
|
|
|
public string SendCar(List<string> carlist, string order_code, string amount)
|
|
|
{
|
|
|
#region 测试屏蔽
|
|
|
//Console.WriteLine($"服务端发车触发 >>> carlist[0]:{carlist.FirstOrDefault()},vin条码:{order_code},车辆长度:{amount}");
|
|
|
//return "11";
|
|
|
#endregion
|
|
|
//通用逻辑:(1 是否空车 2 物料号 3 上件数量)
|
|
|
// 通用逻辑下,下一站点固定(配置)
|
|
|
// -判断小车是否到位,小车已下发去向,清空下发数据信息
|
|
|
// - 判断 小车是否到位,小车未下发去向
|
|
|
// - 进库区判断: 库存是否满;
|
|
|
// -特殊逻辑:下一站点多个站点,按多条线缓存数优先进少的;按物料 + 属性区分进哪个站点,可配置
|
|
|
try
|
|
|
{
|
|
|
var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress);
|
|
|
var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress);
|
|
|
var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress);
|
|
|
var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress);
|
|
|
var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress);
|
|
|
if (carno != null && carstate != null && carrun != null && wcsstate != null && wcsend != null)
|
|
|
{
|
|
|
//正常读到小车信息
|
|
|
if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0)
|
|
|
{
|
|
|
//根据上件点,物料号,获取下一点位信息
|
|
|
var TargetTo = GetTargetTo(Convert.ToInt32(carno), order_code, this.sitenode.siteNo);
|
|
|
//业务处理
|
|
|
if (string.IsNullOrWhiteSpace(TargetTo) || string.IsNullOrWhiteSpace(order_code))
|
|
|
{
|
|
|
//if (string.IsNullOrWhiteSpace(TargetTo)) LogManager.Info($"错误日志输出 >>> 站点:{this.sitenode.siteNo},挂具:{carno}上件车辆去向有误!");
|
|
|
//if (string.IsNullOrWhiteSpace(order_code)) LogManager.Info($"错误日志输出 >>> 站点:{this.sitenode.siteNo},挂具:{carno}Thrift传输Vin码为空!");
|
|
|
Thread.Sleep(1000);
|
|
|
return null;
|
|
|
}
|
|
|
//写入PLC
|
|
|
var ToInt16QuXiang = MainCentralControl.getValue("2", TargetTo);
|
|
|
var ToInt16ChangDu = MainCentralControl.getValue("2", amount);
|
|
|
this._plc.Write(this.NodeSettingCarRun.plcpointAddress, ToInt16QuXiang);//写入小车去向
|
|
|
this._plc.Write(this.NodeSettingWcsSend.plcpointAddress, MainCentralControl.WcsChuLiWanCheng);//写入wms处理完成
|
|
|
this._plc.Write(this.NodeSettingWcsSendMaterial.plcpointAddress, ToInt16ChangDu);//写入车身长度
|
|
|
LogManager.Info($"当前时间 :{DateTime.Now} >>> 上件站点 :{this.sitenode.siteNo}发车 ,挂具号:{carno},去向:{ToInt16QuXiang},Wcs处理完成:{MainCentralControl.WcsChuLiWanCheng},vin条码:{order_code},车身长度:{ToInt16ChangDu}");
|
|
|
return "1";//发车成功反馈
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
LogManager.Error(ex);
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
Thread.Sleep(1000);
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
//根据上件点,物料号,获取下一点位信息
|
|
|
public string GetTargetTo(int carno, string materialNo, string sideno)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
if (string.IsNullOrWhiteSpace(materialNo) || string.IsNullOrWhiteSpace(sideno))
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
using var scope = _host.Services.CreateScope();
|
|
|
using var dbContext = scope.ServiceProvider.GetRequiredService<DefaultDbContext>();
|
|
|
//1 读出点位信息,下一站点
|
|
|
|
|
|
//2 根据物料查下一站点
|
|
|
|
|
|
var WaitdownlineModel = dbContext.BaseWaitdownline.Where(t => t.carNo == carno).FirstOrDefault();
|
|
|
var basecarModel = dbContext.BaseCar.Where(t => t.carNo == carno).FirstOrDefault();
|
|
|
var orderModel = dbContext.BaseProductionOrderSplit.Where(t => t.orderCode == materialNo).FirstOrDefault();
|
|
|
if (WaitdownlineModel == null && basecarModel != null && orderModel != null)//Waitdownline不存在当前车辆信息
|
|
|
{
|
|
|
//添加挂具与物料绑定信息
|
|
|
BaseWaitdownline waitdownModel = new()
|
|
|
{
|
|
|
id = Guid.NewGuid(),
|
|
|
carId = basecarModel.id,
|
|
|
carNo = basecarModel.carNo,
|
|
|
carName = basecarModel.carName,
|
|
|
downline = 1,
|
|
|
materielNo = materialNo,
|
|
|
materielNum = 1,
|
|
|
isDelete = 0,
|
|
|
createTime = DateTime.Now,
|
|
|
createBy = sideno,
|
|
|
definefield1 = orderModel.lineCode
|
|
|
};
|
|
|
dbContext.Add(waitdownModel);
|
|
|
dbContext.SaveChanges();
|
|
|
}
|
|
|
else//Waitdownline存在当前车辆信息即改
|
|
|
{
|
|
|
//base_waitdownline表中挂具与任务VIN码绑定,修改车辆线上状态为已上线
|
|
|
dbContext.BaseWaitdownline.Where(t => t.carNo == carno).Update(a => new BaseWaitdownline() { materielNo = materialNo, materielNum = 1, downline = 1, createBy = sideno, createTime = DateTime.Now, isDelete = 0, definefield1 = orderModel.lineCode });
|
|
|
}
|
|
|
return "1";
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
LogManager.Info($"UpLine类GetTargetTo方法报错 >>> {ex.Message}");
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 返回给客户端车辆到位及车辆信息
|
|
|
/// </summary>
|
|
|
/// <param name="name">无用参数</param>
|
|
|
/// <returns></returns>
|
|
|
public string ReceiveCarNo(string name)
|
|
|
{
|
|
|
|
|
|
try
|
|
|
{
|
|
|
var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress);
|
|
|
var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress);
|
|
|
var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress);
|
|
|
var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress);
|
|
|
var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress);
|
|
|
if (carno != null && carstate != null && carrun != null && wcsstate != null && wcsend != null)
|
|
|
{
|
|
|
if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1)
|
|
|
{
|
|
|
return "";
|
|
|
}
|
|
|
//正常读到小车信息
|
|
|
if (Convert.ToInt32(carno) > 0 && Convert.ToInt32(wcsend) == 0 && Convert.ToInt32(wcsstate) == 0 && Convert.ToInt32(carstate) == 1 && Convert.ToInt32(carrun) == 0)
|
|
|
{
|
|
|
string TuiSongCarNo = carno.ToString();
|
|
|
return TuiSongCarNo;
|
|
|
}
|
|
|
}
|
|
|
Thread.Sleep(1000);
|
|
|
return "";
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
LogManager.Info($"");
|
|
|
return "";
|
|
|
}
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// 启动小车发出后清空预设点位线程
|
|
|
/// </summary>
|
|
|
private void ClearSendCar()
|
|
|
{
|
|
|
while (true)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
var carno = this._plc.Read(NodeSettingCarNo.plcpointAddress);
|
|
|
var carstate = this._plc.Read(NodeSettingCarState.plcpointAddress);
|
|
|
var carrun = this._plc.Read(NodeSettingCarRun.plcpointAddress);
|
|
|
var wcsstate = this._plc.Read(NodeSettingWcsState.plcpointAddress);
|
|
|
var wcsend = this._plc.Read(NodeSettingWcsSend.plcpointAddress);
|
|
|
//清除点位信息
|
|
|
if (Convert.ToInt32(carno) == 0 && Convert.ToInt32(wcsend) == 1 && Convert.ToInt32(wcsstate) == 1)
|
|
|
{
|
|
|
this._plc.Write(NodeSettingCarRun.plcpointAddress, MainCentralControl.QingKongDianWei);
|
|
|
this._plc.Write(NodeSettingWcsSend.plcpointAddress, MainCentralControl.QingKongDianWei);
|
|
|
this._plc.Write(NodeSettingWcsSendMaterial.plcpointAddress, MainCentralControl.QingKongDianWei);
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
LogManager.Info($"发车后清空点位线程报错 >>> {ex.Message}");
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
Thread.Sleep(1000);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|