using ProjectManagementSystem.Common.Config; using ProjectManagementSystem.Common.Extenions; using ProjectManagementSystem.Common.Function; using ProjectManagementSystem.Common.Logger; using ProjectManagementSystem.Common.Models; using ProjectManagementSystem.Common.Models.Crms; using ProjectManagementSystem.Common.Service; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace ProjectManagementSystem.Common.Core { public class PackControlCrms { private static PackControlCrms m_instance; private bool firstStart = true; private bool agvHeartbeat; private uint counter; private bool[] forceWrite = new bool[20]; public double TimeConsumption { get; private set; } public ConcurrentDictionary StationDictionary { get; set; } = new ConcurrentDictionary(); public static PackControlCrms Instance { get { if (m_instance == null) { m_instance = new PackControlCrms(); if (!m_instance.Initialize()) { m_instance = null; } } return m_instance; } } private PackControlCrms() { } private bool Initialize() { try { var assemblyName = this.GetType().Assembly.GetName().Name; var nameSpace = this.GetType().Namespace; string fullClassName = $"{nameSpace}.PackInteractionCrmsBase"; var packInteration = InstanceConstructor.GetInstance(assemblyName, fullClassName); if (packInteration == null) { throw new NullReferenceException("创建的对象为null"); } var configList = ExcelConfig.Instance.RouteConfigList; for (int i = 0; i < configList.Count; i++) { var config = configList[i]; var data = StationDictionary.TryGetValue(config.LocationCode, out var station) ? station : new PackStationV2(); data.Id = config.LocationCode; data.Config = config; var sClassName = config.LocationCode.GetLocationMember("PACK对接类"); if (!string.IsNullOrEmpty(sClassName)) { var sPackInteraction = InstanceConstructor.GetInstance(assemblyName, $"{nameSpace}.{sClassName}"); if (sPackInteraction == null) { throw new NullReferenceException("创建的对象为null"); } data.Interaction = sPackInteraction; } else { data.Interaction = packInteration; } StationDictionary.AddOrUpdate(data.Id, data, (key, value) => data); } Task.Factory.StartNew(UserThread, TaskCreationOptions.LongRunning); return true; } catch (Exception ex) { CLog.Instance.SystemLog.WriteException("PackControl Initialize", ex); } return false; } private void UpdateStationDict() { var packStationInfos = Crms.PmsApi.GetPackStationAGVAll(); if (packStationInfos == null) { Thread.Sleep(5000); return; } var agvDataList = Crms.PmsApi.GetAllCarrier(); if (agvDataList == null) return; var taskList = Crms.PmsApi.GetTaskList(); if (taskList == null) return; var agvDataOnlineList = agvDataList.Where(d => d.Online); var agvDataDict = agvDataList.ToDictionary(d => d.AgvID); var packStationInfoDict = packStationInfos.ToDictionary(d => d.id); foreach (var item in packStationInfos) { if (item.carrierPackStatuses != null) { foreach (var item2 in item.carrierPackStatuses) { agvDataDict.TryGetValue(item2.carrier, out var agvData); item2.AgvData = agvData ?? null; } } } var callHeartbeat = counter % 2 == 0; if (callHeartbeat) { agvHeartbeat = !agvHeartbeat; } DateTime start = DateTime.Now; Parallel.ForEach(StationDictionary.Values, delegate (PackStationV2 data, ParallelLoopState loopState) { try { if (callHeartbeat) { data.Interaction.Heartbeat(data, agvHeartbeat); } packStationInfoDict.TryGetValue(data.Id, out var packStationInfo); data.AgvList = packStationInfo?.carrierPackStatuses; //工位AGV状态变化 if (data.AgvList?.Count > 0) { foreach (var item in data.AgvList) { var lastItem = data.LastAgvList?.FirstOrDefault(d => d.carrier == item.carrier); if (item.agvPositionStatus != lastItem?.agvPositionStatus) { data.Interaction.AgvPositionStatusChanged(data, item, lastItem, taskList); } if (item.agvStationStatus != lastItem?.agvStationStatus) { data.Interaction.AgvStationStatusChanged(data, item, lastItem, taskList); } } } else if (data.LastAgvList?.Count > 0) { foreach (var lastItem in data.LastAgvList) { data.Interaction.AgvPositionStatusChanged(data, null, lastItem, taskList); data.Interaction.AgvStationStatusChanged(data, null, lastItem, taskList); } } data.LastAgvList = data.AgvList; //小车数据 data.AgvApproachingData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.BeforeRequest); data.AgvRequestEnterData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.RequestVertex); data.AgvEnteringData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.Entering); data.AgvAtStationData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.StationVertex); data.AgvLeavingData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.Leaving); data.AgvLeaveDoneData = data.AgvList?.FirstOrDefault(d => d.agvPositionStatus == EPackAgvPositionStatus.ReleaseVertex); data.AgvIdApproaching = data.AgvApproachingData?.carrier ?? 0; data.AgvIdRequestEnter = data.AgvRequestEnterData?.carrier ?? 0; data.AgvIdEntering = data.AgvEnteringData?.carrier ?? 0; data.AgvIdAtStation = data.AgvAtStationData?.carrier ?? 0; data.AgvIdLeaving = data.AgvLeavingData?.carrier ?? 0; data.AgvIdLeaveDone = data.AgvLeaveDoneData?.carrier ?? 0; data.Interaction.CustomProcess(data, firstStart, forceWrite); //工位AGV状态对接 if (data.AgvList != null) { foreach (var item in data.AgvList) { switch (item.agvStationStatus) { case EPackAgvStationStatus.None: break; case EPackAgvStationStatus.WaitTask: data.Interaction.WaitTask(data, item, taskList); break; case EPackAgvStationStatus.WaitEnter: data.Interaction.WaitEnter(data, item, taskList); break; case EPackAgvStationStatus.AtRequest: data.Interaction.AtRequest(data, item, taskList); break; case EPackAgvStationStatus.WaitRequest: data.Interaction.WaitRequest(data, item, taskList); break; case EPackAgvStationStatus.Entering: data.Interaction.Entering(data, item, taskList); break; case EPackAgvStationStatus.AtStation: data.Interaction.AtStation(data, item, taskList); break; case EPackAgvStationStatus.WaitStation: data.Interaction.WaitStation(data, item, taskList); break; case EPackAgvStationStatus.Leaving: data.Interaction.Leaving(data, item, taskList); break; case EPackAgvStationStatus.AtLeave: data.Interaction.AtLeave(data, item, taskList); break; case EPackAgvStationStatus.WaitLeave: data.Interaction.WaitLeave(data, item, taskList); break; default: break; } } } data.Interaction.LastProcess(data); } catch (Exception ex) { data.Message = ex.Message; } data.TimeConsumption = Math.Round((DateTime.Now - start).TotalMilliseconds); }); Parallel.ForEach(agvDataOnlineList, delegate (ResultAgvData agvData, ParallelLoopState loopState) { try { PlcStopAgv(agvData); } catch (Exception) { } }); } private void PlcStopAgv(ResultAgvData agvData) { //查找AGV所在的正在进入和正在离开的所有工位 var stations = StationDictionary.Values.Where(d => { if (d.AgvList == null || d.AgvList.Count == 0) return false; return d.AgvList.Exists(s => s.carrier == agvData.AgvID && (s.agvPositionStatus == EPackAgvPositionStatus.Entering || s.agvPositionStatus == EPackAgvPositionStatus.Leaving)); }).ToList(); if (stations.Count == 0) { return; } string msg = null; //从AGV所在的工位中,获取需要停车的工位 var stopStation = stations.FirstOrDefault(d => { if (d.AgvList.Exists(s => s.carrier == agvData.AgvID && s.agvPositionStatus == EPackAgvPositionStatus.Entering)) { var result = d.Interaction.StopAgvEntering(d, out string tempMsg); msg += $"{d.Config.LocationCode} {tempMsg}; "; if (result) { return true; } } if (d.AgvList.Exists(s => s.carrier == agvData.AgvID && s.agvPositionStatus == EPackAgvPositionStatus.Leaving)) { var result = d.Interaction.StopAgvLeaving(d, out string tempMsg); msg += $"{d.Config.LocationCode} {tempMsg}; "; if (result) { return true; } } return false; }); bool needPauseAgv = stopStation != null; bool agvPaused = agvData.AlarmList?.Exists(d => d.alarmId == 36) ?? false; if (needPauseAgv) { if (!agvPaused) { bool result = Crms.PmsApi.CarrierPause(agvData.AgvID); CLog.Instance.TaskLog.WriteInfo($"{stopStation?.Id} {agvData.AgvID}# 暂停小车{result.ToChineseString()} ({msg})"); } } else { if (agvPaused) { bool result = Crms.PmsApi.CarrierResume(agvData.AgvID); CLog.Instance.TaskLog.WriteInfo($"{stations.FirstOrDefault()?.Id} {agvData.AgvID}# 恢复小车{result.ToChineseString()} ({msg})"); } } } private void UserThread() { CLog.Instance.SystemLog.WriteDebug($"PackControlCrms已启动"); while (true) { DateTime loopStartTime = DateTime.Now; try { //错开刷新 var mod = counter % 20; if (mod >= 0 && mod <= forceWrite.Length) { for (int i = 0; i < forceWrite.Length; i++) { forceWrite[i] = mod == i; } } //DateTime start = DateTime.Now; UpdateStationDict(); //System.Diagnostics.Trace.WriteLine($"UpdateStationDict {string.Join(" ", forces.Select(d => { return d ? "1" : "0"; }))} 耗时:{(DateTime.Now - start).TotalMilliseconds:F1} ms"); } catch (Exception ex) { CLog.Instance.SystemLog.WriteException("PackControlCrms", ex); Thread.Sleep(5000); } firstStart = false; counter++; TimeConsumption = (DateTime.Now - loopStartTime).TotalMilliseconds; Thread.Sleep(500); } } } public class PackStationV2 { public string Id { get; set; } public RouteConfig Config { get; set; } public IPackInteractionCrms Interaction { get; set; } public DateTime LastTaskAddTime { get; set; } public DateTime LastPreTaskAddTime { get; set; } public bool TaskAddCooled { get { return Math.Abs((DateTime.Now - LastTaskAddTime).TotalSeconds) > 5; } } public bool PreTaskAddCooled { get { return Math.Abs((DateTime.Now - LastPreTaskAddTime).TotalSeconds) > 5; } } public List LastAgvList { get; set; } public List AgvList { get; set; } public PackCarrier AgvApproachingData { get; set; } public PackCarrier AgvRequestEnterData { get; set; } public PackCarrier AgvEnteringData { get; set; } public PackCarrier AgvAtStationData { get; set; } public PackCarrier AgvLeavingData { get; set; } public PackCarrier AgvLeaveDoneData { get; set; } public int AgvIdApproaching { get; set; } public int AgvIdRequestEnter { get; set; } public int AgvIdEntering { get; set; } public int AgvIdAtStation { get; set; } public int AgvIdLeaving { get; set; } public int AgvIdLeaveDone { get; set; } public bool AgvApproaching { get; set; } public bool AgvRequestEnter { get; set; } public bool AgvEntering { get; set; } public bool AgvAtStation { get; set; } public bool AgvLeaving { get; set; } public bool AgvLeaveDone { get; set; } public bool AgvInArea { get { return AgvEntering || AgvAtStation || AgvLeaving; } } public bool AgvAtStationRise { get; set; } public bool AgvAtStationFall { get; set; } public int AgvAtStationAgvId { get; set; } public int AgvAtStationAlarmId { get; set; } public bool AgvAtStationAlarm { get; set; } public string AgvAtStationMaterial { get; set; } public string Message { get; set; } public string MessageWaitRequest { get; set; } public string MessageWaitStation { get; set; } public string MessageWaitLeave { get; set; } public double TimeConsumption { get; set; } } public interface IPackInteractionCrms { void Heartbeat(PackStationV2 data, bool agvHeartbeat); void CustomProcess(PackStationV2 data, bool firstStart, bool[] forceWrite); void LastProcess(PackStationV2 data); string GetNextLocation(PackStationV2 data, out string templateName, out string msg); bool StopAgvEntering(PackStationV2 data, out string msg); bool StopAgvLeaving(PackStationV2 data, out string msg); void AgvPositionStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List taskList); void AgvStationStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List taskList); void WaitTask(PackStationV2 data, PackCarrier agv, List taskList); void WaitEnter(PackStationV2 data, PackCarrier agv, List taskList); void AtRequest(PackStationV2 data, PackCarrier agv, List taskList); void WaitRequest(PackStationV2 data, PackCarrier agv, List taskList); void Entering(PackStationV2 data, PackCarrier agv, List taskList); void AtStation(PackStationV2 data, PackCarrier agv, List taskList); void WaitStation(PackStationV2 data, PackCarrier agv, List taskList); void Leaving(PackStationV2 data, PackCarrier agv, List taskList); void AtLeave(PackStationV2 data, PackCarrier agv, List taskList); void WaitLeave(PackStationV2 data, PackCarrier agv, List taskList); void HandleAgvToPlc(PackStationV2 data, PackCarrier agv, string plcAddrDesc, T agvValue); } public class PackInteractionCrmsBase : IPackInteractionCrms { protected int successCode = 20000; protected int unnecessaryCode = -20000; protected int failedCode = -1; protected bool ReadValue(RouteConfig config, string plcAddrDesc, T plcValue, out T readValue, out string msg) { readValue = default(T); if (string.IsNullOrEmpty(config.PlcIpAddr)) { msg = $"没有配置IP地址(PLC)"; return false; } var plcAddr = config.LocationCode.GetLocationMember(plcAddrDesc); if (string.IsNullOrEmpty(plcAddr)) { msg = $"没有配置地址:{plcAddrDesc}"; return false; } if (!config.PlcConnected) { msg = $"PLC未连接"; return false; } var result = config.PlcReadWrite.ReadValue(plcAddr, plcValue, out var read); if (!read.IsSuccess) { msg = $"读取{plcAddrDesc} {plcAddr}失败 Code:{read.ErrorCode} Message:{read.Message}"; return false; } msg = $"读取{plcAddrDesc} {plcAddr} = {read.Content}"; readValue = read.Content; return result; } protected int ReadPlcValue(RouteConfig config, string plcAddrDesc, out string msg) { if (string.IsNullOrEmpty(config.PlcIpAddr)) { msg = $"没有配置IP地址(PLC)"; return unnecessaryCode; } var plcAddr = config.LocationCode.GetLocationMember(plcAddrDesc); if (string.IsNullOrEmpty(plcAddr)) { msg = $"没有配置地址:{plcAddrDesc}"; return unnecessaryCode; } if (!config.PlcConnected) { msg = $"PLC未连接"; return failedCode; } var read = config.PlcReadWrite.ReadBool(plcAddr); if (!read.IsSuccess) { msg = $"读取{plcAddrDesc} {plcAddr}失败 Code:{read.ErrorCode} Message:{read.Message}"; return failedCode; } msg = $"读取{plcAddrDesc} {plcAddr} = {read.Content}"; return read.Content ? successCode : 0; } protected string GetAgvDataString(ResultAgvData agvData) { return agvData == null ? null : $"({agvData.AgvID}# 路段:{agvData.GraphEdge} 导航点:{agvData.GraphVertex})"; } protected string GetAllowStatusString(int allowStatus) { return allowStatus == 1 ? "通行" : "管制"; } public virtual void Heartbeat(PackStationV2 data, bool agvHeartbeat) { //心跳信号处理 var config = data.Config; if (config.PlcConnected && config.PlcReadWrite != null && !string.IsNullOrEmpty(config.PlcHeartbearAddr_AGV)) { var tempResult2 = config.PlcReadWrite.Write(config.PlcHeartbearAddr_AGV, agvHeartbeat); if (!tempResult2.IsSuccess) { CLog.Instance.SystemLog.WriteInfo($"{config.LocationCode} {config.PlcIpAddr} 写入AGV心跳:{tempResult2.IsSuccess.ToChineseString()} {config.PlcHeartbearAddr_AGV} Code:{tempResult2.ErrorCode} Message:{tempResult2.Message}"); } } } public virtual void CustomProcess(PackStationV2 data, bool firstStart, bool[] forceWrite) { //先处理到位AGV相关信息 var agvId = data.AgvAtStationData == null ? 0 : data.AgvAtStationData.carrier; if (data.AgvAtStationAgvId != agvId || firstStart || forceWrite[8]) { data.AgvAtStationAgvId = agvId; data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV编号", (short)data.AgvAtStationAgvId); } var alarmId = data.AgvAtStationData?.AgvData?.AlarmList == null || data.AgvAtStationData.AgvData.AlarmList.Count == 0 ? 0 : data.AgvAtStationData.AgvData.AlarmList.OrderByDescending(d => d.alarmLevel).FirstOrDefault().alarmId; if (data.AgvAtStationAlarmId != alarmId || firstStart || forceWrite[9]) { data.AgvAtStationAlarmId = alarmId; data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV报警代码", (short)data.AgvAtStationAlarmId); } var agvAlarm = alarmId > 0; if (data.AgvAtStationAlarm != agvAlarm || firstStart || forceWrite[10]) { data.AgvAtStationAlarm = agvAlarm; data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV报警", data.AgvAtStationAlarm); } if (!string.IsNullOrWhiteSpace(data.Id.GetLocationMember("AGV物料"))) { string agvMaterial = string.Empty; if (agvId > 0) { var res = Crms.PmsTaskService.GetAgvMaterial(new AgvMaterialDto { AgvId = agvId }); var agvMaterialDto = res?.data as AgvMaterialDto; agvMaterial = agvMaterialDto?.MaterialBarcode ?? string.Empty; } if (data.AgvAtStationMaterial != agvMaterial || firstStart || forceWrite[11]) { data.AgvAtStationMaterial = agvMaterial; data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV物料", data.AgvAtStationMaterial); } } //工位相关信号 var result = data.AgvApproachingData != null; if (data.AgvApproaching != result || firstStart || forceWrite[0]) { data.AgvApproaching = result; data.Interaction.HandleAgvToPlc(data, data.AgvApproachingData, "AGV正在接近", data.AgvApproaching); } result = data.AgvRequestEnterData != null; if (data.AgvRequestEnter != result || firstStart || forceWrite[1]) { data.AgvRequestEnter = result; data.Interaction.HandleAgvToPlc(data, data.AgvRequestEnterData, "AGV请求进入", data.AgvRequestEnter); } result = data.AgvEnteringData != null; if (data.AgvEntering != result || firstStart || forceWrite[2]) { data.AgvEntering = result; data.Interaction.HandleAgvToPlc(data, data.AgvEnteringData, "AGV正在进入", data.AgvEntering); } result = data.AgvAtStationData != null; if (data.AgvAtStation != result || firstStart || forceWrite[3]) { data.AgvAtStation = result; data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV到位", data.AgvAtStation); } result = data.AgvLeavingData != null; if (data.AgvLeaving != result || firstStart || forceWrite[4]) { data.AgvLeaving = result; data.Interaction.HandleAgvToPlc(data, data.AgvLeavingData, "AGV正在离开", data.AgvLeaving); } result = data.AgvLeaveDoneData != null; if (data.AgvLeaveDone != result || firstStart || forceWrite[5]) { data.AgvLeaveDone = result; data.Interaction.HandleAgvToPlc(data, data.AgvLeaveDoneData, "AGV离开完成", data.AgvLeaveDone); } //LogicBit 9 上升到位状态 512 //LogicBit 10 下降到位状态 1024 result = data.AgvAtStationData?.AgvData != null ? data.AgvAtStationData.AgvData.LogicBits.GetBitVaule(9) : false; if (data.AgvAtStationRise != result || firstStart || forceWrite[6]) { data.AgvAtStationRise = result; data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV上升到位", data.AgvAtStationRise); } result = data.AgvAtStationData?.AgvData != null ? data.AgvAtStationData.AgvData.LogicBits.GetBitVaule(10) : false; if (data.AgvAtStationFall != result || firstStart || forceWrite[7]) { data.AgvAtStationFall = result; data.Interaction.HandleAgvToPlc(data, data.AgvAtStationData, "AGV下降到位", data.AgvAtStationFall); } } public virtual void LastProcess(PackStationV2 data) { //消息清理 if (data.AgvIdAtStation == 0) { data.Message = null; } if (data.AgvIdApproaching == 0 && data.AgvIdRequestEnter == 0) { data.MessageWaitRequest = null; } if (data.AgvIdEntering == 0 && data.AgvIdAtStation == 0) { data.MessageWaitStation = null; } if (data.AgvIdLeaving == 0 && data.AgvIdLeaveDone == 0) { data.MessageWaitLeave = null; } } public virtual string GetNextLocation(PackStationV2 data, out string templateName, out string msg) { var config = data.Config; templateName = null; var result = ReadPlcValue(config, "PLC放行", out msg); if (result <= 0) { return null; } string nextLocation = config.LocationCode.GetLocationMember("下个工位"); if (string.IsNullOrWhiteSpace(nextLocation)) { msg = $"{msg} 没配置下个工位"; return null; } nextLocation = nextLocation.ToValueArray()[0]; //有放行信号 var result2 = ReadPlcValue(config, "PLC返修", out var msg2); msg = $"{msg} {msg2}"; if (result2 == unnecessaryCode || result2 == 0) { templateName = config.LocationCode.GetLocationMember("后任务模板"); return nextLocation; } if (result2 < 0) { return null; } string ngLocation = config.LocationCode.GetLocationMember("返修工位"); if (string.IsNullOrWhiteSpace(ngLocation)) { msg = $"{msg} 没配置返修工位"; return null; } templateName = config.LocationCode.GetLocationMember("返修任务模板"); return ngLocation.ToValueArray()[0]; } public virtual bool StopAgvEntering(PackStationV2 data, out string msg) { var result = ReadPlcValue(data.Config, "PLC急停", out msg); if (result == failedCode || result == 0) { return true; } result = ReadPlcValue(data.Config, "PLC进入互锁", out msg); if (result == failedCode || result == 0) { return true; } return false; } public virtual bool StopAgvLeaving(PackStationV2 data, out string msg) { var result = ReadPlcValue(data.Config, "PLC急停", out msg); if (result == failedCode || result == 0) { return true; } result = ReadPlcValue(data.Config, "PLC离开互锁", out msg); if (result == failedCode || result == 0) { return true; } return false; } public virtual void AgvPositionStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List taskList) { var config = data.Config; CLog.Instance.TaskLog.WriteDebug($"{config.LocationCode} 位置状态 {lastAgv?.agvPositionStatus} -> {agv?.agvPositionStatus} {GetAgvDataString(agv?.AgvData)}"); } public virtual void AgvStationStatusChanged(PackStationV2 data, PackCarrier agv, PackCarrier lastAgv, List taskList) { var config = data.Config; CLog.Instance.TaskLog.WriteDebug($"{config.LocationCode} 工位状态 {lastAgv?.agvStationStatus} -> {agv?.agvStationStatus} {GetAgvDataString(agv?.AgvData)}"); } public virtual void WaitTask(PackStationV2 data, PackCarrier agv, List taskList) { if (!data.PreTaskAddCooled) return; if (agv.AgvData?.Status != 0) return; if (taskList.FirstOrDefault(d => d.Carrier == agv.carrier || d.BindingAGVNumber == agv.carrier) != null) return; var config = data.Config; CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} 添加前置任务 {GetAgvDataString(agv.AgvData)}"); PmsTaskInfoDto dto = new PmsTaskInfoDto(); dto.LocationCode = data.Id; dto.TargetLocationCode = data.Id; dto.Carrier = agv.carrier; dto.CarrierType = "0"; dto.TemplateName = config.LocationCode.GetLocationMember("前任务模板"); Crms.PmsTaskService.TaskAddNoCheck(dto, new string[] { }); data.LastPreTaskAddTime = DateTime.Now; } public virtual void WaitEnter(PackStationV2 data, PackCarrier agv, List taskList) { } public virtual void AtRequest(PackStationV2 data, PackCarrier agv, List taskList) { } public virtual void WaitRequest(PackStationV2 data, PackCarrier agv, List taskList) { if (agv.enter == 1) return; var config = data.Config; var result = ReadPlcValue(config, "PLC允许进入", out var msg); var allowStatus = result > 0 ? 1 : 0; msg = $"{msg} {GetAgvDataString(agv.AgvData)}"; if (agv.enter != allowStatus) { var result2 = Crms.PmsApi.AllowAgv(data.Id, agv.carrier, allowStatus, 0, 0); msg = $"{msg} 请求点{GetAllowStatusString(allowStatus)}{result2.ToChineseString()}"; } if (data.MessageWaitRequest != msg) { CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {msg}"); } data.MessageWaitRequest = msg; } public virtual void Entering(PackStationV2 data, PackCarrier agv, List taskList) { } public virtual void AtStation(PackStationV2 data, PackCarrier agv, List taskList) { if (!data.TaskAddCooled) return; if (taskList.FirstOrDefault(d => d.TaskType != ETaskType.Charge && (d.Carrier == agv.carrier || d.BindingAGVNumber == agv.carrier)) != null) return; var nextLocation = GetNextLocation(data, out var templateName, out var msg); if (data.Message != msg) { CLog.Instance.TaskLog.WriteInfo($"{data.Id} {msg} {GetAgvDataString(agv.AgvData)}"); } data.Message = msg; if (string.IsNullOrWhiteSpace(nextLocation)) { return; } PmsTaskInfoDto dto = new PmsTaskInfoDto(); dto.LocationCode = data.Id; dto.TargetLocationCode = nextLocation; dto.Carrier = agv.carrier; dto.CarrierType = "0"; dto.TemplateName = templateName; Crms.PmsTaskService.TaskAddNoCheck(dto, new string[] { }); data.LastTaskAddTime = DateTime.Now; data.Message = null; } public virtual void WaitStation(PackStationV2 data, PackCarrier agv, List taskList) { if (agv.leaver == 1) return; var config = data.Config; var result = ReadPlcValue(config, "PLC放行", out var msg); var allowStatus = result > 0 ? 1 : 0; msg = $"{msg} {GetAgvDataString(agv.AgvData)}"; if (agv.leaver != allowStatus) { var result2 = Crms.PmsApi.AllowAgv(data.Id, agv.carrier, 0, allowStatus, 0); msg = $"{msg} 工位点{GetAllowStatusString(allowStatus)}{result2.ToChineseString()}"; } if (data.MessageWaitStation != msg) { CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {msg}"); } data.MessageWaitStation = msg; } public virtual void Leaving(PackStationV2 data, PackCarrier agv, List taskList) { } public virtual void AtLeave(PackStationV2 data, PackCarrier agv, List taskList) { } public virtual void WaitLeave(PackStationV2 data, PackCarrier agv, List taskList) { if (agv.release == 1) return; var config = data.Config; var result = ReadPlcValue(config, "PLC离开完成", out var msg); var allowStatus = result > 0 ? 1 : 0; msg = $"{msg} {GetAgvDataString(agv.AgvData)}"; if (agv.release != allowStatus) { var result2 = Crms.PmsApi.AllowAgv(data.Id, agv.carrier, 0, 0, allowStatus); msg = $"{msg} 释放点{GetAllowStatusString(allowStatus)}{result2.ToChineseString()}"; } if (data.MessageWaitLeave != msg) { CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {msg}"); } data.MessageWaitLeave = msg; } public virtual void HandleAgvToPlc(PackStationV2 data, PackCarrier agv, string plcAddrDesc, T agvValue) { var config = data.Config; if (!config.PlcConnected || config.PlcReadWrite == null) return; string plcAddr = config.LocationCode.GetLocationMember(plcAddrDesc); if (string.IsNullOrWhiteSpace(plcAddr)) return; var readResult = config.PlcReadWrite.ReadValue(plcAddr, agvValue, out var _); if (readResult) return; var result = config.PlcReadWrite.WriteValue(plcAddr, agvValue); var agvInfo = GetAgvDataString(agv?.AgvData); CLog.Instance.TaskLog.WriteInfo($"{config.LocationCode} {plcAddrDesc} {plcAddr} = {agvValue} 写入{result.IsSuccess.ToChineseString()} {agvInfo}"); } } }