Files
WCS/Plugins/Wcs/Plugin.Cowain.Wcs/Services/RgvTaskService.cs
2026-03-02 09:13:29 +08:00

577 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Cowain.Base.DBContext;
using Cowain.Base.Helpers;
using Cowain.Base.Models;
using Cowain.Base.Services;
using HslCommunication.Core;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Plugin.Cowain.Driver.Abstractions;
using Plugin.Cowain.Driver.Models.Enum;
using Plugin.Cowain.Driver.ViewModels;
using Plugin.Cowain.Wcs.Actions;
using Plugin.Cowain.Wcs.IServices;
using Plugin.Cowain.Wcs.Models;
using Plugin.Cowain.Wcs.Models.Dto;
using Plugin.Cowain.Wcs.Models.Enum;
using Plugin.Cowain.Wcs.ViewModels;
using System.Text;
namespace Plugin.Cowain.Wcs.Services;
public class WcsToRgvData
{
public short Command { get; set; }
public short Count { get; set; }
public int TaskId { get; set; }
public short ToStation { get; set; }
public string QrCode { get; set; } = string.Empty;
}
public class RgvTaskService : BaseService, IRgvTaskService
{
private IServiceScopeFactory _scopeFactory;
private IDeviceMonitor _deviceMonitor;
private readonly ILogger<RgvTaskService> _logger;
public RgvTaskService(SqlDbContext dbContext, IDeviceMonitor deviceMonitor, IServiceScopeFactory scopeFactory, ILogger<RgvTaskService> logger) : base(dbContext)
{
_scopeFactory = scopeFactory;
_deviceMonitor = deviceMonitor;
_logger = logger;
}
public List<RgvActionViewModel>? ActionToList(string action)
{
try
{
var actions = JsonConvert.DeserializeObject<List<string>>(action) ?? [];
var rgvActionViewModels = actions
.Select((name, i) => new RgvActionViewModel { Id = i + 1, Name = name })
.ToList();
rgvActionViewModels.Insert(0, new RgvActionViewModel { Id = 0, Name = RgvCommandEnum.UnKnown.ToString() });
return rgvActionViewModels;
}
catch (Exception ex)
{
_logger.LogError(ex, "反序列化失败");
return null;
}
}
public RgvCommandEnum GetStepAction(List<RgvActionViewModel> actions, int step)
{
var name = actions.FirstOrDefault(x => x.Id == step)?.Name;
return Enum.TryParse(name, out RgvCommandEnum cmd) ? cmd : RgvCommandEnum.UnKnown;
}
public async Task<ResultModel> FinishTaskAsync(int id)
{
if (id <= 0)
{
return ResultModel.Error("id不能小于0");
}
var DbSet = _dBContext.GetDbSet<TaskDataDto>();
var existingModel = await DbSet.FirstOrDefaultAsync(x => x.Id == id);
if (existingModel == null)
{
return ResultModel.Error("Taskid不存在");
}
existingModel.IsFinished = true;
int count = await _dBContext.SaveChangesAsync();
return count > 0 ? ResultModel.Success("Task直接更新为结束") : ResultModel.Error("Task直接更新为结束失败");
}
public async Task<List<TaskViewModel>> GetAllAsync()
{
var DbSet = _dBContext.GetDbSet<TaskDataDto>();
var data = await DbSet.ToListAsync();
return new List<TaskViewModel>(data.Select(x => new TaskViewModel
{
Id = x.Id,
ProcessId = x.ProcessId,
ProcessName = x.ProcessName,
Priority = x.Priority,
FromStationId = x.FromStationId,
ToStationId = x.ToStationId,
FromStatus = x.FromStatus,
ToStatus = x.ToStatus,
CreatTime = x.CreateTime,
IsFinished = x.IsFinished,
ExecuteAction = x.ExecuteAction,
FinishedTime = x.FinishedTime,
QrCode = x.QrCode,
//Actions = new(ActionToList(x.Action) ?? new List<RgvActionViewModel>()),
Action = x.Action
}));
}
public async Task<(List<TaskViewModel>, int totals)> GetAllAsync(int pageIndex, int pageSize)
{
var DbSet = _dBContext.GetDbSet<TaskDataDto>();
// 按照CreateTime倒序排列最新的任务排第一个
var data = await DbSet.OrderByDescending(x => x.CreateTime).ToListAsync();
var list = data.Skip((pageIndex - 1) * pageSize).Take(pageSize);
var ret = new List<TaskViewModel>(list.Select(x => new TaskViewModel
{
Id = x.Id,
ProcessId = x.ProcessId,
ProcessName = x.ProcessName,
Priority = x.Priority,
FromStationId = x.FromStationId,
ToStationId = x.ToStationId,
FromStatus = x.FromStatus,
ToStatus = x.ToStatus,
CreatTime = x.CreateTime,
IsFinished = x.IsFinished,
ExecuteAction = x.ExecuteAction,
FinishedTime = x.FinishedTime,
QrCode = x.QrCode,
Action = x.Action,
//Actions = new(ActionToList(x.Action) ?? new List<RgvActionViewModel>())
}));
return (ret, data.Count());
}
public async Task<ResultModel<RgvCommandModel>> GetRgvCommandAsync(RgvUpdateInfoModel? infoModel)
{
RgvCommandModel? rgvCommand = null;
if (infoModel == null)
{
return ResultModel<RgvCommandModel>.Error("RgvUpdateInfoModel不能为空");
}
using var scope = _scopeFactory.CreateScope();
var dBContext = scope.ServiceProvider.GetRequiredService<SqlDbContext>();
var taskSet = dBContext.GetDbSet<TaskDataDto>();
var unfinishedTask = await taskSet.AsNoTracking().FirstOrDefaultAsync(t => !t.IsFinished);
if (unfinishedTask == null)
{
_logger.LogInformation($"没有找到在执行的任务,不需要处理");
return ResultModel<RgvCommandModel>.Error("没有找到在执行的任务,不需要处理");
}
int step = 0;
if (infoModel.Source == RgvUpdateSourceEnum.PLC)
{
if (infoModel.RetResult == 2)
{
_logger.LogInformation($"PLC反馈结果是NG,任务id={unfinishedTask.Id}");
return ResultModel<RgvCommandModel>.Error($"PLC反馈结果是NG,任务id={unfinishedTask.Id}");
}
else if (infoModel.TaskId != unfinishedTask.Id)
{
_logger.LogInformation($"PLC反馈结果任务号不匹配plc任务号={infoModel.TaskId},执行任务id={unfinishedTask.Id}");
return ResultModel<RgvCommandModel>.Error($"PLC反馈结果任务号不匹配plc任务号={infoModel.TaskId},执行任务id={unfinishedTask.Id}");
}
step = unfinishedTask.ExecuteAction;
}
else if (infoModel.Source == RgvUpdateSourceEnum.First)
{
step = 0;
}
else if (infoModel.Source == RgvUpdateSourceEnum.User)
{
//手动下发的任务
if (infoModel.ExecuteAction > 0)
{
step = infoModel.ExecuteAction - 1;
}
else
{
_logger.LogInformation($"手动选择的动作不能为0");
return ResultModel<RgvCommandModel>.Error($"手动选择的动作不能为0");
}
}
try
{
var actionResult = ActionToList(unfinishedTask.Action); //转换动作列表
if (actionResult == null)
{
_logger.LogInformation($"工艺未配置Action请修改taskId={unfinishedTask.Id}");
return ResultModel<RgvCommandModel>.Error($"工艺未配置Action请修改taskId={unfinishedTask.Id}");
}
var actions = actionResult;
var stationService = scope.ServiceProvider.GetRequiredService<IStationService>();
var stationTaskHandler = scope.ServiceProvider.GetRequiredService<IEnumerable<IHostedService>>();
var stationQueueHostedService = stationTaskHandler.OfType<StationQueueHostedService>().FirstOrDefault();
var stations = await stationService.GetAllAsync();
var fromStation = stations.FirstOrDefault(x => x.Id == unfinishedTask.FromStationId);
if (fromStation == null)
{
return ResultModel<RgvCommandModel>.Error($"From工站不存在工站Id={unfinishedTask.FromStationId}");
}
var toStation = stations.FirstOrDefault(x => x.Id == unfinishedTask.ToStationId);
if (toStation == null)
{
return ResultModel<RgvCommandModel>.Error($"To工站不存在工站Id={unfinishedTask.ToStationId}");
}
//数据库存储的是上一步
var stepCommand = GetStepAction(actions, step); //获取上一步动作
var nextCommand = GetStepAction(actions, step + 1); //获取下一步动作
if (infoModel.Source == RgvUpdateSourceEnum.PLC)
{
if (infoModel.RetCmd != (int)stepCommand)
{
_logger.LogInformation($"PLC反馈动作不正确PLC动作{infoModel.RetCmd},实际动作{(int)stepCommand}");
return ResultModel<RgvCommandModel>.Error($"PLC反馈动作不正确PLC动作{infoModel.RetCmd},实际动作{(int)stepCommand}");
}
}
if (stepCommand == RgvCommandEnum.UnKnown && nextCommand == RgvCommandEnum.UnKnown)
{
_logger.LogInformation($"获取RGV命令失败配置有误");
return ResultModel<RgvCommandModel>.Error("获取RGV命令失败配置有误");
}
if (nextCommand == RgvCommandEnum.Move)
{
//下一步是移动
var moveNextCommand = GetStepAction(actions, step + 2); //获取下一步动作
if (moveNextCommand == RgvCommandEnum.UnKnown)
{
rgvCommand = new RgvCommandModel { Command = nextCommand, TargetPos = toStation.StationPos };
}
else if (moveNextCommand == RgvCommandEnum.PickIn || moveNextCommand == RgvCommandEnum.PickOut)
{
rgvCommand = new RgvCommandModel { Command = nextCommand, TargetPos = fromStation.StationPos };
}
else if (moveNextCommand == RgvCommandEnum.PlaceIn || moveNextCommand == RgvCommandEnum.PlaceOut)
{
rgvCommand = new RgvCommandModel { Command = nextCommand, TargetPos = toStation.StationPos };
}
}
else if (nextCommand == RgvCommandEnum.PickIn || nextCommand == RgvCommandEnum.PickOut)
{
rgvCommand = new RgvCommandModel { Command = nextCommand, TargetPos = fromStation.StationPos };
}
else if (nextCommand == RgvCommandEnum.PlaceIn || nextCommand == RgvCommandEnum.PlaceOut)
{
rgvCommand = new RgvCommandModel { Command = nextCommand, TargetPos = toStation.StationPos };
}
else if (nextCommand == RgvCommandEnum.UnKnown)
{
//没有下一步动作,说明任务结束
rgvCommand = new RgvCommandModel { Command = RgvCommandEnum.UnKnown };
}
if (rgvCommand == null)
{
_logger.LogInformation($"获取RGV命令失败配置有误");
return ResultModel<RgvCommandModel>.Error("获取RGV命令失败配置有误");
}
rgvCommand.QrCode = unfinishedTask.QrCode;
var processService = scope.ServiceProvider.GetRequiredService<IProcessService>();
var getJson = await processService.GetJsonData(unfinishedTask.ProcessId);
string? rgvName = string.Empty;
if (getJson != null)
{
rgvName = getJson.Data!.RgvName;
}
//更新RGV
if (stepCommand == RgvCommandEnum.Move)
{
if (nextCommand == RgvCommandEnum.PickIn || nextCommand == RgvCommandEnum.PickOut)
{
//更新rgv的目标位置
var rgvService = scope.ServiceProvider.GetRequiredService<IRgvService>();
var rgvs = await rgvService.GetAllAsync();
if (rgvs != null)
{
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
if (rgv != null)
{
rgv.LayOutX = fromStation.LayOutX;
await rgvService.UpdateAsync(rgv);
}
}
}
else if (nextCommand == RgvCommandEnum.PlaceIn || nextCommand == RgvCommandEnum.PlaceOut)
{
//更新rgv的目标位置
var rgvService = scope.ServiceProvider.GetRequiredService<IRgvService>();
var rgvs = await rgvService.GetAllAsync();
if (rgvs != null)
{
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
if (rgv != null)
{
rgv.LayOutX = toStation.LayOutX;
await rgvService.UpdateAsync(rgv);
}
}
}
}
//更新工站状态
if (stepCommand == RgvCommandEnum.UnKnown && nextCommand == RgvCommandEnum.Move)
{
//【1】上一步未知下一步是移动任务刚开始
fromStation.UpdateSource = StationUpdateSourceEnum.Task;
fromStation.Status = StationStateEnum.Picking.ToString();
toStation.UpdateSource = StationUpdateSourceEnum.Task;
toStation.Status = StationStateEnum.Placing.ToString();
stationQueueHostedService?.Enqueue(fromStation);
stationQueueHostedService?.Enqueue(toStation);
//任务刚开始更新Rgv
var rgvService = scope.ServiceProvider.GetRequiredService<IRgvService>();
var rgvs = await rgvService.GetAllAsync();
if (rgvs != null)
{
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
if (rgv != null)
{
rgv.FromStationId = fromStation.Id;
rgv.ToStationId = toStation.Id;
rgv.ProcessName = unfinishedTask.ProcessName;
await rgvService.UpdateAsync(rgv);
}
}
}
else if ((stepCommand == RgvCommandEnum.PickIn || stepCommand == RgvCommandEnum.PickOut) && nextCommand != RgvCommandEnum.PickIn && nextCommand != RgvCommandEnum.PickOut)
{
//【2】下一步要放料将源QR复制到目标QR
toStation.UpdateSource = StationUpdateSourceEnum.Task;
toStation.QrCode = fromStation.QrCode;
fromStation.Status = StationStateEnum.PickFinished.ToString();
stationQueueHostedService?.Enqueue(fromStation);
}
else if ((stepCommand == RgvCommandEnum.PlaceIn || stepCommand == RgvCommandEnum.PlaceOut) && nextCommand == RgvCommandEnum.UnKnown)
{
//【3】上一步是放料动作下一步无动作说明任务结束
toStation.UpdateSource = StationUpdateSourceEnum.Task;
toStation.Status = StationStateEnum.PlaceFinished.ToString();
stationQueueHostedService?.Enqueue(toStation);
var rgvService = scope.ServiceProvider.GetRequiredService<IRgvService>();
var rgvs = await rgvService.GetAllAsync();
if (rgvs != null)
{
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
if (rgv != null)
{
rgv.FromStationId = 0;
rgv.ToStationId = 0;
rgv.ProcessName = "";
await rgvService.UpdateAsync(rgv);
}
}
}
int save = 0;
if (rgvCommand.Command == RgvCommandEnum.UnKnown)
{
//没有目标动作,说明任务结束
unfinishedTask.IsFinished = true;
unfinishedTask.FinishedTime = DateTime.Now;
// 手动将实体状态标记为Modified
dBContext.Entry(unfinishedTask).State = EntityState.Modified;
save = await dBContext.SaveChangesAsync();
if (save > 0)
{
_logger.LogInformation($"任务完成任务id={unfinishedTask.Id}");
}
}
else
{
rgvCommand.TaskId = unfinishedTask.Id;
unfinishedTask.ExecuteAction = step + 1;
// 手动将实体状态标记为Modified
dBContext.Entry(unfinishedTask).State = EntityState.Modified;
save = await dBContext.SaveChangesAsync();
if (save > 0)
{
_logger.LogInformation($"任务继续任务id={unfinishedTask.Id},动作={JsonConvert.SerializeObject(rgvCommand)}");
}
}
if (save > 0)
{
return ResultModel<RgvCommandModel>.Success(rgvCommand);
}
else
{
return ResultModel<RgvCommandModel>.Error($"任务更新异常任务id={unfinishedTask.Id}");
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"任务异常任务id={unfinishedTask.Id}");
return ResultModel<RgvCommandModel>.Error($"任务异常任务id={unfinishedTask.Id}");
}
}
public async Task<ResultModel> ExecuteAsync(string? actionParam, RgvUpdateSourceEnum source, int? execute = 0)
{
if (string.IsNullOrEmpty(actionParam))
{
return ResultModel.Error("参数不能为空");
}
try
{
var _param = JsonConvert.DeserializeObject<RgvFinishedParamData>(actionParam);
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.RetCmdAddress);
if (!read.IsSuccess)
{
_logger.LogError($"从PLC读取调度数据失败{_param.PlcName}->{_param.RetCmdAddress}{read.ErrorMessage}");
return ResultModel.Error($"读命令失败:{_param.PlcName}->{_param.RetCmdAddress}{read.ErrorMessage}");
}
RgvUpdateInfoModel updateInfo = new RgvUpdateInfoModel
{
Source = source,
TaskId = read.Data.TaskId,
RetResult = read.Data.Result,
RetCmd = read.Data.Command,
ExecuteAction = execute == null ? 0 : execute.Value,
};
var rgvCommand = await GetRgvCommandAsync(updateInfo);
var readToRgvData = await ReadToRgvDataAsync(plc, _param.CmdAddress);
if (!readToRgvData.IsSuccess)
{
_logger.LogError($"从PLC读取命令失败{_param.PlcName}->{_param.CmdAddress}{read.ErrorMessage}");
return ResultModel.Error($"从PLC读取命令失败{_param.PlcName}->{_param.CmdAddress}{read.ErrorMessage}");
}
short count = readToRgvData.Data.Count; //计数
if (source == RgvUpdateSourceEnum.First && count != 1)
{
//新任务,且计数不为1重置计数,这个情况出现在任务生成后被手动结束了
count = 0;
}
count = count + 1 <= 100 ? (short)(count + 1) : (short)1; //最大100
if (rgvCommand.IsSuccess)
{
if (rgvCommand.Data!.Command != RgvCommandEnum.UnKnown)
{
WcsToRgvData wcsToRgv = new WcsToRgvData
{
Command = (short)rgvCommand.Data!.Command,
Count = count,
ToStation = (short)rgvCommand.Data!.TargetPos,
TaskId = rgvCommand.Data!.TaskId,
QrCode = rgvCommand.Data!.QrCode,
};
var write = await WriteAsync(plc, _param.CmdAddress, wcsToRgv);
if (!write.IsSuccess) return ResultModel.Error($"写变量失败:{_param.PlcName}->{_param.CmdAddress}");
_logger.LogInformation($"调度任务下发成功TaskId={wcsToRgv.TaskId}->{JsonConvert.SerializeObject(wcsToRgv)}");
return ResultModel.Success();
}
}
return ResultModel.Error($"没有需要执行的动作TaskId={updateInfo.TaskId}");
}
catch (Exception ex)
{
return ResultModel.Error($"参数解析失败:{ex.Message}");
}
}
[LogAndSwallow]
private async Task<ResultModel<RgvToWcsData>> ReadAsync(IReadWriteDevice driver, string address)
{
var readResult = await driver.ReadAsync(address, 10);
if (!readResult.IsSuccess)
{
ResultModel<RgvToWcsData>.Error(readResult.Message);
}
RgvToWcsData requestData = new RgvToWcsData
{
Command = driver.ByteTransform.TransInt16(readResult.Content, 0),
Count = driver.ByteTransform.TransInt16(readResult.Content, 2),
Result = driver.ByteTransform.TransInt16(readResult.Content, 4),
TaskId = driver.ByteTransform.TransInt32(readResult.Content, 6)
};
return ResultModel<RgvToWcsData>.Success(requestData);
}
[LogAndSwallow]
private async Task<ResultModel<WcsToRgvData>> ReadToRgvDataAsync(IReadWriteDevice driver, string address)
{
var readResult = await driver.ReadAsync(address, 40);
if (!readResult.IsSuccess)
{
ResultModel<WcsToRgvData>.Error(readResult.Message);
}
WcsToRgvData requestData = new WcsToRgvData
{
Command = driver.ByteTransform.TransInt16(readResult.Content, 0),
Count = driver.ByteTransform.TransInt16(readResult.Content, 14),
TaskId = driver.ByteTransform.TransInt32(readResult.Content, 6)
};
return ResultModel<WcsToRgvData>.Success(requestData);
}
[LogAndSwallow]
private async Task<ResultModel> WriteAsync(IReadWriteDevice driver, string address, WcsToRgvData toRgvData, int retryCount = 5)
{
// 准备数据
byte[] data = new byte[40];
driver.ByteTransform.TransByte(toRgvData.Command).CopyTo(data, 0);
driver.ByteTransform.TransByte(toRgvData.TaskId).CopyTo(data, 2);
driver.ByteTransform.TransByte(toRgvData.ToStation).CopyTo(data, 10);
driver.ByteTransform.TransByte(toRgvData.Count).CopyTo(data, 14);
data[16] = 20;//字符串最大长度
data[17] = (byte)toRgvData.QrCode.Length;//字符串实际长度
Encoding.ASCII.GetBytes(toRgvData.QrCode).CopyTo(data, 18);
int baseDelay = 100; // 基础延迟100ms
var random = new Random();
for (int retry = 0; retry < retryCount; retry++)
{
var write = await driver.WriteAsync(address, data);
if (write.IsSuccess)
{
if (retry > 1)
{
//第一次就成功,不需要记录日志
_logger.LogInformation($"写PLC数据调度任务成功{address}->{JsonConvert.SerializeObject(toRgvData)},第{retry + 1}次尝试");
}
return ResultModel.Success();
}
else
{
_logger.LogError($"写PLC数据调度任务失败{address}->{JsonConvert.SerializeObject(toRgvData)},第{retry + 1}次尝试");
}
// 如果不是最后一次尝试,则等待后重试
if (retry < retryCount - 1)
{
// 计算指数退避+抖动
int jitter = random.Next(0, 100); // 0~100ms
int delay = baseDelay * (int)Math.Pow(2, retry) + jitter;
await Task.Delay(delay);
}
}
_logger.LogError($"写PLC数据调度任务失败{address}->{JsonConvert.SerializeObject(toRgvData)},总共{retryCount}次尝试");
return ResultModel.Error("写PLC数据失败");
}
}