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; }
}