using Cowain.Base.Models; using HslCommunication; using HslCommunication.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Plugin.Cowain.Driver; using Plugin.Cowain.Driver.Abstractions; using Plugin.Cowain.Driver.Attributes; using Plugin.Cowain.Driver.Models; using Plugin.Cowain.Wcs.IServices; using Plugin.Cowain.Wcs.Models.Enum; using Plugin.Cowain.Wcs.Services; using System.Text.Json; namespace Plugin.Cowain.Wcs.Actions; /// /// 工站需要上下料请求 /// [Action("Station", "工站请求命令")] public class StationAction : IVariableAction { private class ParamData { /// /// PLC名称 /// public string StationCode { get; set; } = string.Empty; /// /// PLC名称 /// public string PlcName { get; set; } = string.Empty; /// /// 命令地址 /// public string CmdAddress { get; set; } = string.Empty; /// /// 反馈命令地址 /// public string RetCmdAddress { get; set; } = string.Empty; } private readonly IDeviceMonitor _deviceMonitor; private IServiceScopeFactory _scopeFactory; private readonly ILogger _logger; public StationAction(IDeviceMonitor deviceMonitor, IServiceScopeFactory scopeFactory, ILogger logger) { _deviceMonitor = deviceMonitor; _scopeFactory = scopeFactory; _logger = logger; } public async Task ExecuteAsync(VariableAction variableAction, CancellationToken cancellationToken) { _logger.LogInformation($"执行测试事件:{variableAction.Variable.Name}-{variableAction.Variable.Address},参数:{variableAction.Param},旧值:{variableAction.Variable.OldValue},新值:{variableAction.Variable.Value}"); var _param = JsonSerializer.Deserialize(variableAction.Param); if (_param == null) { return ResultModel.Error("参数解析失败"); } var driver = _deviceMonitor.GetDriver(_param.PlcName); if (!driver.IsSuccess) { return ResultModel.Error($"未找到名称为 {_param.PlcName} 的Driver"); } var plc = driver.Data.GetReadWrite(); if (plc == null) { return ResultModel.Error($"GetReadWrite为空,PLC={_param.PlcName}"); } var read = await ReadAsync(plc, _param.CmdAddress); if (!read.IsSuccess) { _logger.LogError($"从PLC读取工站数据失败:{_param.PlcName}->{_param.CmdAddress},{read.ErrorMessage}"); return ResultModel.Error($"读命令失败:{_param.PlcName}->{_param.CmdAddress},{read.ErrorMessage}"); } using var scope = _scopeFactory.CreateScope(); var stationService = scope.ServiceProvider.GetRequiredService(); var stations = await stationService.GetAllAsync(); var station = stations.FirstOrDefault(x => x.StationCode == _param.StationCode); if (station == null) { _logger.LogError($"工站不存在,请检查:{_param.StationCode}"); return ResultModel.Error($"工站不存在,请检查:{_param.StationCode}"); } station.UpdateSource = StationUpdateSourceEnum.PLC; if (read.Data.Command == (short)StationStateEnum.RequestPick) { station.Status = StationStateEnum.RequestPick.ToString(); station.QrCode = read.Data.QrCode; } else if (read.Data.Command == (short)StationStateEnum.RequestPlace) { station.Status = StationStateEnum.RequestPlace.ToString(); } else if (read.Data.Command == (short)StationStateEnum.NgPick) { station.Status = StationStateEnum.NgPick.ToString(); station.QrCode = read.Data.QrCode; } else if (read.Data.Command == 1) { //清除工站信息 station.QrCode = ""; station.ProcessName = ""; station.Status = StationStateEnum.UnKnown.ToString(); } else { _logger.LogError($"命令不正确,请检查:{_param.StationCode},{read.Data.Command}"); return ResultModel.Error($"命令不正确,请检查:{_param.StationCode},{read.Data.Command}"); } station.ProcessName = read.Data.ProcessName; //这里没有判断产品名称是否正确,如果不正确需要返回PLC NG,待完善 _logger.LogInformation($"工站更新开始:{_param.StationCode},{read.Data.Command}"); var stationTaskHandler = scope.ServiceProvider.GetRequiredService>(); var stationQueueHostedService = stationTaskHandler.OfType().FirstOrDefault(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); station.UpdatedAction = result => tcs.TrySetResult(result); stationQueueHostedService?.Enqueue(station); var ret = await tcs.Task; _logger.LogInformation($"工站更新结束:{_param.StationCode},{read.Data.Command}"); //使用批量写入,保证PLC数据一致性,避免出现部分数据未写成功的情况,要么都没写成功 if (ret) { //工站更新OK var writeResult = await plc.WriteValuesAysnc(_param.RetCmdAddress, new short[] { read.Data.Command, (short)1, read.Data.Count }); } else { //工站更新NG var writeResult = await plc.WriteValuesAysnc(_param.RetCmdAddress, new short[] { read.Data.Command, (short)2, read.Data.Count }); } return ResultModel.Success(); } private async Task> ReadAsync(IReadWriteDevice driver, string address) { var readResult = await driver.ReadAsync(address, 70); if (!readResult.IsSuccess) { ResultModel.Error(readResult.Message); } StationRequestData requestData = new StationRequestData { Command = driver.ByteTransform.TransInt16(readResult.Content, 0), Count = driver.ByteTransform.TransInt16(readResult.Content, 2), ProcessName = readResult.Content.RemoveBegin(4).GetS7String(), NgStationName = readResult.Content.RemoveBegin(26).GetS7String(), QrCode = readResult.Content.RemoveBegin(48).GetS7String() }; return ResultModel.Success(requestData); } } public class StationRequestData { public string QrCode { get; set; } = string.Empty; public string ProcessName { get; set; } = string.Empty; public string NgStationName { get; set; } = string.Empty; public short Command { get; set; } public short Count { get; set; } }