202 lines
6.5 KiB
C#
202 lines
6.5 KiB
C#
using Grpc.Core;
|
|
using MudBlazor;
|
|
using RobotApp.Services.Exceptions;
|
|
using RobotApp.VDA5050.Factsheet;
|
|
using RobotApp.VDA5050.InstantAction;
|
|
using RobotApp.VDA5050.State;
|
|
using RobotApp.VDA5050.Type;
|
|
|
|
namespace RobotApp.Services.Robot.Actions;
|
|
|
|
public abstract class RobotAction(IServiceProvider serviceProvider) : IDisposable
|
|
{
|
|
public ActionType Type { get; private set; }
|
|
public string Id { get; private set; } = "";
|
|
public string Description { get; private set; } = "";
|
|
public BlockingType BlockingType { get; private set; }
|
|
public ActionParameter[] Parameters { get; private set; } = [];
|
|
public ActionStatus Status { get; protected set; } = ActionStatus.WAITING;
|
|
public string ResultDescription { get; set; } = "";
|
|
public bool IsCompleted => Status == ActionStatus.FINISHED || Status == ActionStatus.FAILED;
|
|
public ActionScopes ActionScope { get; set; }
|
|
|
|
private WatchTimerAsync<RobotAction>? ActionTimer;
|
|
private const int ActionInterval = 200;
|
|
|
|
protected IServiceProvider ServiceProvider = serviceProvider;
|
|
protected VDA5050.InstantAction.Action? Action;
|
|
protected IServiceScope? Scope;
|
|
protected Logger<RobotAction>? Logger;
|
|
protected AgvAction? AgvAction;
|
|
protected bool IsPaused = false;
|
|
protected ActionStatus HistoryStatus;
|
|
|
|
private bool IsCancelAction = false;
|
|
|
|
public bool Initialize(ActionScopes actionScope, VDA5050.InstantAction.Action action)
|
|
{
|
|
Status = ActionStatus.WAITING;
|
|
ActionScope = actionScope;
|
|
Action = action;
|
|
Initialize();
|
|
Id = Action.ActionId;
|
|
Description = Action.ActionDescription;
|
|
Status = ActionStatus.WAITING;
|
|
return true;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
if (Status != ActionStatus.WAITING) return;
|
|
Scope ??= ServiceProvider.CreateScope();
|
|
Logger = Scope.ServiceProvider.GetRequiredService<Logger<RobotAction>>();
|
|
ActionTimer = new(ActionInterval, ActionHandler, Logger);
|
|
Status = ActionStatus.INITIALIZING;
|
|
ActionTimer.Start();
|
|
}
|
|
|
|
public void Pause()
|
|
{
|
|
HistoryStatus = Status;
|
|
Status = ActionStatus.PAUSED;
|
|
IsPaused = true;
|
|
}
|
|
|
|
public void Resume()
|
|
{
|
|
if (Status == ActionStatus.PAUSED) Status = ActionStatus.WAITING;
|
|
}
|
|
|
|
public void Cancel()
|
|
{
|
|
if (!IsCompleted) IsCancelAction = true;
|
|
if (Status == ActionStatus.WAITING) StopAction();
|
|
}
|
|
|
|
public async Task WaitAsync(CancellationToken cancellationToken)
|
|
{
|
|
while (!cancellationToken.IsCancellationRequested && !IsCompleted)
|
|
{
|
|
await Task.Delay(500, cancellationToken).ConfigureAwait(false);
|
|
}
|
|
}
|
|
|
|
public void Wait(CancellationToken cancellationToken)
|
|
{
|
|
while (!cancellationToken.IsCancellationRequested && !IsCompleted)
|
|
{
|
|
Task.Delay(500, cancellationToken).Wait(cancellationToken);
|
|
}
|
|
}
|
|
|
|
protected virtual Task StartAction()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
protected virtual Task StopAction()
|
|
{
|
|
Console.WriteLine($"StopAction {Type}");
|
|
Status = ActionStatus.FAILED;
|
|
ResultDescription = "Action bị hủy bỏ.";
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
protected virtual Task ExecuteAction()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
protected virtual Task PauseAction()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
protected virtual Task ResumeAction()
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
protected virtual void Initialize()
|
|
{
|
|
if (Action is null) throw new ActionException("Khởi tạo Action không tồn tại");
|
|
Scope ??= ServiceProvider.CreateScope();
|
|
var FactsheetService = Scope.ServiceProvider.GetRequiredService<RobotFactsheet>();
|
|
|
|
if (Enum.TryParse(Action.ActionType, out ActionType type)) Type = type;
|
|
else throw new ActionException($"ActionType {Action.ActionType} không hợp lệ.");
|
|
|
|
var actionStore = FactsheetService.GetAction(Type) ?? throw new ActionException($"ActionType {Action.ActionType} không được thiết kế.");
|
|
|
|
if (Enum.TryParse(Action.BlockingType, out BlockingType blockingType)) BlockingType = blockingType;
|
|
else throw new ActionException($"BlockingType {Action.BlockingType} không hợp lệ.");
|
|
|
|
if (!actionStore.BlockingTypes.Any(bt => bt == BlockingType.ToString())) throw new ActionException($"BlockingType {BlockingType} không được hỗ trợ cho action {Type}.");
|
|
if (!actionStore.ActionScopes.Any(sp => sp == ActionScope.ToString())) throw new ActionException($"ActionScope {ActionScope} không được hỗ trợ cho action {Type}.");
|
|
|
|
if (actionStore.ActionParameters.Length > 0)
|
|
{
|
|
foreach (var parameterStore in actionStore.ActionParameters)
|
|
{
|
|
if (!parameterStore.IsOptional)
|
|
{
|
|
if (!Action.ActionParameters.Any(a => a.Key == parameterStore.Key)) throw new ActionException($"Thiếu tham số bắt buộc '{parameterStore.Key}' cho action {Type}.");
|
|
}
|
|
}
|
|
Parameters = Action.ActionParameters;
|
|
}
|
|
AgvAction = actionStore;
|
|
}
|
|
|
|
private async Task ActionHandler()
|
|
{
|
|
try
|
|
{
|
|
if (IsCancelAction)
|
|
{
|
|
await StopAction();
|
|
}
|
|
else
|
|
{
|
|
if (Status == ActionStatus.INITIALIZING)
|
|
{
|
|
Logger?.Info($"Thực hiện action {Type}");
|
|
Status = ActionStatus.RUNNING;
|
|
await StartAction();
|
|
}
|
|
else if (Status == ActionStatus.RUNNING)
|
|
{
|
|
await ExecuteAction();
|
|
}
|
|
else if (Status == ActionStatus.PAUSED)
|
|
{
|
|
await PauseAction();
|
|
}
|
|
else if (Status == ActionStatus.WAITING && IsPaused)
|
|
{
|
|
await ResumeAction();
|
|
}
|
|
}
|
|
|
|
if (IsCompleted)
|
|
{
|
|
Dispose();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger?.Error($"Thực hiện action {Type} xảy ra lỗi: {ex.Message}");
|
|
Status = ActionStatus.FAILED;
|
|
ResultDescription = $"Thực hiện action {Type} xảy ra lỗi: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!IsCompleted) StopAction();
|
|
ActionTimer?.Dispose();
|
|
ActionTimer = null;
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|