634 lines
27 KiB
C#
634 lines
27 KiB
C#
using Cowain.Base.DBContext;
|
||
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.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 RgvToWcsData
|
||
{
|
||
public short Command { get; set; }
|
||
public short Count { get; set; }
|
||
public short Result { get; set; }
|
||
public int TaskId { get; set; }
|
||
}
|
||
|
||
public class WcsToRgv6180Data
|
||
{
|
||
public short Command { get; set; }
|
||
public short Count { get; set; }
|
||
public int TaskId { get; set; }
|
||
public short FromStation1 { get; set; }
|
||
public short FromStation2 { get; set; }
|
||
public short ToStation1 { get; set; }
|
||
public short ToStation2 { get; set; }
|
||
public string QrCode1 { get; set; } = string.Empty;
|
||
public string QrCode2 { get; set; } = string.Empty;
|
||
}
|
||
|
||
|
||
public class RgvTask6180Service : BaseService, IRgvTask6180Service
|
||
{
|
||
private IServiceScopeFactory _scopeFactory;
|
||
private IDeviceMonitor _deviceMonitor;
|
||
private readonly ILogger<RgvTask6180Service> _logger;
|
||
|
||
public RgvTask6180Service(SqlDbContext dbContext, IDeviceMonitor deviceMonitor, IServiceScopeFactory scopeFactory, ILogger<RgvTask6180Service> 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 = RgvCommand6180Enum.UnKnown.ToString() });
|
||
return rgvActionViewModels;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, "反序列化失败");
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public RgvCommand6180Enum GetStepAction(List<RgvActionViewModel> actions, int step)
|
||
{
|
||
var name = actions.FirstOrDefault(x => x.Id == step)?.Name;
|
||
return Enum.TryParse(name, out RgvCommand6180Enum cmd) ? cmd : RgvCommand6180Enum.UnKnown;
|
||
}
|
||
|
||
public async Task<ResultModel> FinishTaskAsync(int id)
|
||
{
|
||
if (id <= 0)
|
||
{
|
||
return ResultModel.Error("id不能小于0");
|
||
}
|
||
var DbSet = _dBContext.GetDbSet<TaskData6180Dto>();
|
||
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<Task6180ViewModel>> GetAllAsync()
|
||
{
|
||
var DbSet = _dBContext.GetDbSet<TaskData6180Dto>();
|
||
var data = await DbSet.ToListAsync();
|
||
return new List<Task6180ViewModel>(data.Select(x => new Task6180ViewModel
|
||
{
|
||
Id = x.Id,
|
||
ProcessId = x.ProcessId,
|
||
ProcessName = x.ProcessName,
|
||
Priority = x.Priority,
|
||
FromStationId1 = x.FromStationId1,
|
||
ToStationId1 = x.ToStationId1,
|
||
FromStatus1 = x.FromStatus1,
|
||
ToStatus1 = x.ToStatus1,
|
||
FromStationId2 = x.FromStationId2,
|
||
ToStationId2 = x.ToStationId2,
|
||
FromStatus2 = x.FromStatus2,
|
||
ToStatus2 = x.ToStatus2,
|
||
CreatTime = x.CreateTime,
|
||
IsFinished = x.IsFinished,
|
||
ExecuteAction = x.ExecuteAction,
|
||
FinishedTime = x.FinishedTime,
|
||
QrCode1 = x.QrCode1,
|
||
QrCode2 = x.QrCode2,
|
||
Action = x.Action
|
||
}));
|
||
}
|
||
|
||
public async Task<(List<Task6180ViewModel>, int totals)> GetAllAsync(int pageIndex, int pageSize)
|
||
{
|
||
var DbSet = _dBContext.GetDbSet<TaskData6180Dto>();
|
||
// 按照CreateTime倒序排列,最新的任务排第一个
|
||
var data = await DbSet.OrderByDescending(x => x.Id).ToListAsync();
|
||
var list = data.Skip((pageIndex - 1) * pageSize).Take(pageSize);
|
||
var ret = new List<Task6180ViewModel>(list.Select(x => new Task6180ViewModel
|
||
{
|
||
Id = x.Id,
|
||
ProcessId = x.ProcessId,
|
||
ProcessName = x.ProcessName,
|
||
Priority = x.Priority,
|
||
FromStationId1 = x.FromStationId1,
|
||
ToStationId1 = x.ToStationId1,
|
||
FromStatus1 = x.FromStatus1,
|
||
ToStatus1 = x.ToStatus1,
|
||
FromStationId2 = x.FromStationId2,
|
||
ToStationId2 = x.ToStationId2,
|
||
FromStatus2 = x.FromStatus2,
|
||
ToStatus2 = x.ToStatus2,
|
||
CreatTime = x.CreateTime,
|
||
IsFinished = x.IsFinished,
|
||
ExecuteAction = x.ExecuteAction,
|
||
FinishedTime = x.FinishedTime,
|
||
QrCode1 = x.QrCode1,
|
||
QrCode2 = x.QrCode2,
|
||
Action = x.Action
|
||
//Actions = new(ActionToList(x.Action) ?? new List<RgvActionViewModel>())
|
||
}));
|
||
|
||
return (ret, data.Count());
|
||
|
||
}
|
||
|
||
public async Task<ResultModel<RgvCommand6180Model>> GetRgvCommandAsync(RgvUpdateInfoModel? infoModel)
|
||
{
|
||
RgvCommand6180Model? rgvCommand = null;
|
||
if (infoModel == null)
|
||
{
|
||
return ResultModel<RgvCommand6180Model>.Error("RgvUpdateInfoModel不能为空");
|
||
}
|
||
using var scope = _scopeFactory.CreateScope();
|
||
var dBContext = scope.ServiceProvider.GetRequiredService<SqlDbContext>();
|
||
var taskSet = dBContext.GetDbSet<TaskData6180Dto>();
|
||
var unfinishedTask = await taskSet.AsNoTracking().FirstOrDefaultAsync(t => !t.IsFinished);
|
||
|
||
if (unfinishedTask == null)
|
||
{
|
||
_logger.LogInformation($"没有找到在执行的任务,不需要处理");
|
||
return ResultModel<RgvCommand6180Model>.Error("没有找到在执行的任务,不需要处理");
|
||
}
|
||
var actionResult = ActionToList(unfinishedTask.Action); //转换动作列表
|
||
if (actionResult == null)
|
||
{
|
||
_logger.LogError($"工艺未配置Action,请修改,taskId={unfinishedTask.Id}");
|
||
return ResultModel<RgvCommand6180Model>.Error($"工艺未配置Action,请修改,taskId={unfinishedTask.Id}");
|
||
}
|
||
var actions = actionResult;
|
||
int step = 0;
|
||
if (infoModel.Source == RgvUpdateSourceEnum.PLC)
|
||
{
|
||
if (infoModel.RetResult == 2)
|
||
{
|
||
_logger.LogError($"PLC反馈结果是NG,任务id={unfinishedTask.Id}");
|
||
return ResultModel<RgvCommand6180Model>.Error($"PLC反馈结果是NG,任务id={unfinishedTask.Id}");
|
||
}
|
||
else if (infoModel.TaskId != unfinishedTask.Id)
|
||
{
|
||
_logger.LogError($"PLC反馈结果任务号不匹配,plc任务号={infoModel.TaskId},执行任务id={unfinishedTask.Id}");
|
||
return ResultModel<RgvCommand6180Model>.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;
|
||
_logger.LogInformation($"手动下发任务,执行任务id={unfinishedTask.Id}:{GetStepAction(actions, step).ToString()}");
|
||
}
|
||
else
|
||
{
|
||
_logger.LogError($"手动选择的动作不能为0");
|
||
return ResultModel<RgvCommand6180Model>.Error($"手动选择的动作不能为0");
|
||
}
|
||
}
|
||
|
||
try
|
||
{
|
||
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 fromStation1 = stations.FirstOrDefault(x => x.Id == unfinishedTask.FromStationId1);
|
||
if (fromStation1 == null)
|
||
{
|
||
return ResultModel<RgvCommand6180Model>.Error($"From1工站不存在,工站Id={unfinishedTask.FromStationId1}");
|
||
}
|
||
var toStation1 = stations.FirstOrDefault(x => x.Id == unfinishedTask.ToStationId1);
|
||
if (toStation1 == null)
|
||
{
|
||
return ResultModel<RgvCommand6180Model>.Error($"To1工站不存在,工站Id={unfinishedTask.ToStationId1}");
|
||
}
|
||
var fromStation2 = stations.FirstOrDefault(x => x.Id == unfinishedTask.FromStationId2);
|
||
if (unfinishedTask.FromStationId2 > 0 && fromStation2 == null)
|
||
{
|
||
return ResultModel<RgvCommand6180Model>.Error($"From2工站不存在,工站Id={unfinishedTask.FromStationId2}");
|
||
}
|
||
var toStation2 = stations.FirstOrDefault(x => x.Id == unfinishedTask.ToStationId2);
|
||
if (unfinishedTask.ToStationId2 > 0 && toStation2 == null)
|
||
{
|
||
return ResultModel<RgvCommand6180Model>.Error($"To2站不存在,工站Id={unfinishedTask.ToStationId2}");
|
||
}
|
||
|
||
//数据库存储的是上一步
|
||
var stepCommand = GetStepAction(actions, step); //获取上一步动作
|
||
var nextCommand = GetStepAction(actions, step + 1); //获取下一步动作
|
||
|
||
if (infoModel.Source == RgvUpdateSourceEnum.PLC)
|
||
{
|
||
if (infoModel.RetCmd != (int)stepCommand)
|
||
{
|
||
_logger.LogError($"PLC反馈动作不正确,PLC动作{infoModel.RetCmd},实际动作{(int)stepCommand}");
|
||
return ResultModel<RgvCommand6180Model>.Error($"PLC反馈动作不正确,PLC动作{infoModel.RetCmd},实际动作{(int)stepCommand}");
|
||
}
|
||
}
|
||
|
||
if (stepCommand == RgvCommand6180Enum.UnKnown && nextCommand == RgvCommand6180Enum.UnKnown)
|
||
{
|
||
_logger.LogError($"获取RGV命令失败,配置有误");
|
||
return ResultModel<RgvCommand6180Model>.Error("获取RGV命令失败,配置有误");
|
||
}
|
||
|
||
rgvCommand = new RgvCommand6180Model
|
||
{
|
||
Command = nextCommand,
|
||
TaskId = unfinishedTask.Id,
|
||
FromPos1 = fromStation1.StationPos,
|
||
FromPos2 = fromStation2?.StationPos ?? 0,
|
||
TargetPos1 = toStation1.StationPos,
|
||
TargetPos2 = toStation2?.StationPos ?? 0,
|
||
QrCode1 = unfinishedTask.QrCode1,
|
||
QrCode2 = unfinishedTask.QrCode2
|
||
};
|
||
|
||
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 == RgvCommand6180Enum.MoveFrom)
|
||
{
|
||
//更新rgv的目标位置
|
||
var rgvService = scope.ServiceProvider.GetRequiredService<IRgv6180Service>();
|
||
var rgvs = await rgvService.GetAllAsync();
|
||
if (rgvs != null)
|
||
{
|
||
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
|
||
if (rgv != null)
|
||
{
|
||
rgv.LayOutX = fromStation1.LayOutX;
|
||
await rgvService.UpdateAsync(rgv);
|
||
}
|
||
}
|
||
}
|
||
else if (stepCommand == RgvCommand6180Enum.MoveTo)
|
||
{
|
||
//更新rgv的目标位置
|
||
var rgvService = scope.ServiceProvider.GetRequiredService<IRgv6180Service>();
|
||
var rgvs = await rgvService.GetAllAsync();
|
||
if (rgvs != null)
|
||
{
|
||
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
|
||
if (rgv != null)
|
||
{
|
||
rgv.LayOutX = toStation1.LayOutX;
|
||
await rgvService.UpdateAsync(rgv);
|
||
}
|
||
}
|
||
}
|
||
|
||
//更新工站状态
|
||
if (stepCommand == RgvCommand6180Enum.UnKnown && nextCommand != RgvCommand6180Enum.UnKnown)
|
||
{
|
||
//【1】上一步未知,任务刚开始
|
||
fromStation1.UpdateSource = StationUpdateSourceEnum.Task;
|
||
fromStation1.Status = StationStateEnum.Picking.ToString();
|
||
toStation1.UpdateSource = StationUpdateSourceEnum.Task;
|
||
toStation1.Status = StationStateEnum.Placing.ToString();
|
||
stationQueueHostedService?.Enqueue(fromStation1);
|
||
stationQueueHostedService?.Enqueue(toStation1);
|
||
if (fromStation2 != null)
|
||
{
|
||
fromStation2.UpdateSource = StationUpdateSourceEnum.Task;
|
||
fromStation2.Status = StationStateEnum.Picking.ToString();
|
||
stationQueueHostedService?.Enqueue(fromStation2);
|
||
}
|
||
if (toStation2 != null)
|
||
{
|
||
toStation2.UpdateSource = StationUpdateSourceEnum.Task;
|
||
toStation2.Status = StationStateEnum.Placing.ToString();
|
||
stationQueueHostedService?.Enqueue(toStation2);
|
||
}
|
||
|
||
//任务刚开始,更新Rgv
|
||
var rgvService = scope.ServiceProvider.GetRequiredService<IRgv6180Service>();
|
||
var rgvs = await rgvService.GetAllAsync();
|
||
if (rgvs != null)
|
||
{
|
||
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
|
||
if (rgv != null)
|
||
{
|
||
rgv.FromStationId1 = fromStation1.Id;
|
||
rgv.ToStationId1 = toStation1.Id;
|
||
rgv.FromStationId2 = fromStation2?.Id ?? 0;
|
||
rgv.ToStationId2 = toStation2?.Id ?? 0;
|
||
rgv.ProcessName = unfinishedTask.ProcessName;
|
||
await rgvService.UpdateAsync(rgv);
|
||
}
|
||
}
|
||
}
|
||
else if (nextCommand == RgvCommand6180Enum.Place)
|
||
{
|
||
//【2】下一步要放料,将源QR复制到目标QR
|
||
toStation1.UpdateSource = StationUpdateSourceEnum.Task;
|
||
toStation1.QrCode = fromStation1.QrCode;
|
||
stationQueueHostedService?.Enqueue(toStation1);
|
||
if (fromStation2 != null && toStation2 != null)
|
||
{
|
||
toStation2.UpdateSource = StationUpdateSourceEnum.Task;
|
||
toStation2.QrCode = fromStation2.QrCode;
|
||
stationQueueHostedService?.Enqueue(toStation2);
|
||
}
|
||
|
||
}
|
||
else if (stepCommand == RgvCommand6180Enum.Pick && nextCommand != RgvCommand6180Enum.Pick)
|
||
{
|
||
//【3】取料完成
|
||
fromStation1.UpdateSource = StationUpdateSourceEnum.Task;
|
||
fromStation1.Status = StationStateEnum.PickFinished.ToString();
|
||
stationQueueHostedService?.Enqueue(fromStation1);
|
||
|
||
if (fromStation2 != null)
|
||
{
|
||
fromStation2.UpdateSource = StationUpdateSourceEnum.Task;
|
||
fromStation2.Status = StationStateEnum.PickFinished.ToString();
|
||
stationQueueHostedService?.Enqueue(fromStation2);
|
||
}
|
||
}
|
||
else if (stepCommand == RgvCommand6180Enum.Place && nextCommand != RgvCommand6180Enum.Place)
|
||
{
|
||
//【4】放料完成,任务结束
|
||
toStation1.UpdateSource = StationUpdateSourceEnum.Task;
|
||
toStation1.Status = StationStateEnum.PlaceFinished.ToString();
|
||
stationQueueHostedService?.Enqueue(toStation1);
|
||
if (toStation2 != null)
|
||
{
|
||
toStation2.UpdateSource = StationUpdateSourceEnum.Task;
|
||
toStation2.Status = StationStateEnum.PlaceFinished.ToString();
|
||
stationQueueHostedService?.Enqueue(toStation2);
|
||
}
|
||
|
||
var rgvService = scope.ServiceProvider.GetRequiredService<IRgv6180Service>();
|
||
var rgvs = await rgvService.GetAllAsync();
|
||
if (rgvs != null)
|
||
{
|
||
var rgv = rgvs.FirstOrDefault(x => x.StationName == rgvName);
|
||
if (rgv != null)
|
||
{
|
||
rgv.FromStationId1 = 0;
|
||
rgv.ToStationId1 = 0;
|
||
rgv.FromStationId2 = 0;
|
||
rgv.ToStationId2 = 0;
|
||
rgv.ProcessName = "";
|
||
await rgvService.UpdateAsync(rgv);
|
||
}
|
||
}
|
||
}
|
||
int save = 0;
|
||
if (stepCommand == RgvCommand6180Enum.Place && nextCommand == RgvCommand6180Enum.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<RgvCommand6180Model>.Success(rgvCommand);
|
||
}
|
||
else
|
||
{
|
||
return ResultModel<RgvCommand6180Model>.Error($"任务更新异常,任务id={unfinishedTask.Id}");
|
||
}
|
||
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogError(ex, $"任务异常,任务id={unfinishedTask.Id}");
|
||
return ResultModel<RgvCommand6180Model>.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<RgvFinished6180ParamData>(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);
|
||
|
||
RgvUpdateInfoModel updateInfo = new RgvUpdateInfoModel
|
||
{
|
||
Source = source,
|
||
TaskId = read.IsSuccess ? read.Data.TaskId : 0,
|
||
RetResult = read.IsSuccess ? read.Data.Result : 0,
|
||
RetCmd = read.IsSuccess ? read.Data.Command : 0,
|
||
ExecuteAction = execute == null ? 0 : execute.Value,
|
||
};
|
||
var rgvCommand = await GetRgvCommandAsync(updateInfo);
|
||
if (!read.IsSuccess)
|
||
{
|
||
_logger.LogError($"从PLC读取调度数据失败:{_param.PlcName}->{_param.RetCmdAddress},{read.ErrorMessage}");
|
||
return ResultModel.Error($"读命令失败:{_param.PlcName}->{_param.RetCmdAddress},{read.ErrorMessage}");
|
||
}
|
||
|
||
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 != RgvCommand6180Enum.UnKnown)
|
||
{
|
||
WcsToRgv6180Data wcsToRgv = new WcsToRgv6180Data
|
||
{
|
||
Command = (short)rgvCommand.Data!.Command,
|
||
Count = count,
|
||
FromStation1 = (short)rgvCommand.Data!.FromPos1,
|
||
FromStation2 = (short)rgvCommand.Data!.FromPos2,
|
||
ToStation1 = (short)rgvCommand.Data!.TargetPos1,
|
||
ToStation2 = (short)rgvCommand.Data!.TargetPos2,
|
||
TaskId = rgvCommand.Data!.TaskId,
|
||
QrCode1 = rgvCommand.Data!.QrCode1,
|
||
QrCode2 = rgvCommand.Data!.QrCode2
|
||
};
|
||
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)
|
||
{
|
||
return 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<WcsToRgv6180Data>> ReadToRgvDataAsync(IReadWriteDevice driver, string address)
|
||
{
|
||
var readResult = await driver.ReadAsync(address, 60);
|
||
if (!readResult.IsSuccess)
|
||
{
|
||
return ResultModel<WcsToRgv6180Data>.Error(readResult.Message);
|
||
}
|
||
WcsToRgv6180Data requestData = new WcsToRgv6180Data
|
||
{
|
||
Command = driver.ByteTransform.TransInt16(readResult.Content, 0),
|
||
Count = driver.ByteTransform.TransInt16(readResult.Content, 14),
|
||
TaskId = driver.ByteTransform.TransInt32(readResult.Content, 6)
|
||
};
|
||
return ResultModel<WcsToRgv6180Data>.Success(requestData);
|
||
}
|
||
|
||
[LogAndSwallow]
|
||
private async Task<ResultModel> WriteAsync(IReadWriteDevice driver, string address, WcsToRgv6180Data toRgvData, int retryCount = 5)
|
||
{
|
||
// 准备数据
|
||
byte[] data = new byte[60];
|
||
driver.ByteTransform.TransByte(toRgvData.Command).CopyTo(data, 0);
|
||
driver.ByteTransform.TransByte(toRgvData.TaskId).CopyTo(data, 2);
|
||
driver.ByteTransform.TransByte(toRgvData.FromStation1).CopyTo(data, 6);
|
||
driver.ByteTransform.TransByte(toRgvData.FromStation2).CopyTo(data, 8);
|
||
driver.ByteTransform.TransByte(toRgvData.ToStation1).CopyTo(data, 10);
|
||
driver.ByteTransform.TransByte(toRgvData.ToStation2).CopyTo(data, 12);
|
||
driver.ByteTransform.TransByte(toRgvData.Count).CopyTo(data, 14);
|
||
data[16] = 20;//字符串最大长度
|
||
data[17] = (byte)toRgvData.QrCode1.Length;//字符串实际长度
|
||
Encoding.ASCII.GetBytes(toRgvData.QrCode1).CopyTo(data, 18);
|
||
data[38] = 20;//字符串最大长度
|
||
data[39] = (byte)toRgvData.QrCode2.Length;//字符串实际长度
|
||
Encoding.ASCII.GetBytes(toRgvData.QrCode2).CopyTo(data, 40);
|
||
|
||
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数据失败");
|
||
}
|
||
|
||
}
|