Vda5050ProtocolService.cs 5.81 KB
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Rcs.Application.Common;
using Rcs.Application.Services.Protocol;
using Rcs.Application.Shared;
using Rcs.Domain.Entities;
using Rcs.Domain.Models.VDA5050;

namespace Rcs.Infrastructure.Services.Protocol;

/// <summary>
/// VDA5050协议服务实现
/// 通过MQTT与机器人通信
/// @author zzy
/// </summary>
public class Vda5050ProtocolService : IProtocolService
{
    private readonly ILogger<Vda5050ProtocolService> _logger;
    private readonly IMqttClientService _mqttClientService;
    private IProtocolService _protocolServiceImplementation;

    public Vda5050ProtocolService(
        ILogger<Vda5050ProtocolService> logger,
        IMqttClientService mqttClientService)
    {
        _logger = logger;
        _mqttClientService = mqttClientService;
    }

    /// <summary>
    /// 支持的协议类型:VDA5050
    /// </summary>
    public ProtocolType ProtocolType => ProtocolType.VDA;

    public async Task<ApiResponse> SendOrderAsync(Robot robot, RobotTask task, CancellationToken ct = default)
    {
        _logger.LogInformation("VDA5050 - 发送Order,机器人: {SerialNumber}, 订单: {OrderId}",
            robot.RobotSerialNumber, task.TaskCode);
        return ApiResponse.Successful();
    }

    /// <summary>
    /// 取消指定订单(通过发送cancelOrder即时动作)
    /// </summary>
    public async Task CancelOrderAsync(Robot robot, string? orderId, CancellationToken ct = default)
    {
        _logger.LogInformation("VDA5050 - 取消订单,机器人: {SerialNumber}, 订单: {OrderId}",
            robot.RobotSerialNumber, orderId);

        var instantAction = CreateInstantAction(robot, "cancelOrder");
        await SendInstantActionAsync(robot, instantAction, ct);
    }

    /// <summary>
    /// 取消机器人所有任务
    /// </summary>
    public async Task CancelRobotTasksAsync(Robot robot, CancellationToken ct = default)
    {
        _logger.LogInformation("VDA5050 - 取消所有任务,机器人: {SerialNumber}", robot.RobotSerialNumber);

        var instantAction = CreateInstantAction(robot, "cancelOrder");
        await SendInstantActionAsync(robot, instantAction, ct);
    }

    /// <summary>
    /// 发送即时动作指令
    /// </summary>
    public async Task SendInstantActionAsync(Robot robot, InstantAction actions, CancellationToken ct = default)
    {
        _logger.LogInformation("VDA5050 - 发送InstantAction,机器人: {SerialNumber}, 动作数: {Count}",
            robot.RobotSerialNumber, actions.Actions.Count);

        var payload = JsonSerializer.Serialize(actions);
        await _mqttClientService.PublishInstantActionsAsync(
            robot.ProtocolName,
            robot.ProtocolVersion,
            robot.RobotManufacturer,
            robot.RobotSerialNumber,
            payload,
            ct: ct);
    }

    /// <summary>
    /// 复位机器人(通过发送stateRequest即时动作)
    /// </summary>
    public async Task ResetRobotAsync(Robot robot, CancellationToken ct = default)
    {
        _logger.LogInformation("VDA5050 - 复位机器人: {SerialNumber}", robot.RobotSerialNumber);

        var instantAction = CreateInstantAction(robot, "stateRequest");
        await SendInstantActionAsync(robot, instantAction, ct);
    }

    /// <summary>
    /// 确认异常(VDA5050协议无此操作,记录日志)
    /// </summary>
    public Task ConfirmExceptionAsync(Robot robot, CancellationToken ct = default)
    {
        _logger.LogInformation("VDA5050 - 确认异常(协议无此操作),机器人: {SerialNumber}", robot.RobotSerialNumber);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 构建VDA5050 Order消息
    /// @author zzy
    /// </summary>
    private Order BuildVdaOrder(RobotTask task, Robot robot)
    {
        var order = new Order
        {
            HeaderId = (int)(robot.HeaderId + 1),
            Timestamp = DateTime.UtcNow.ToString("O"),
            Version = robot.ProtocolVersion,
            Manufacturer = robot.RobotManufacturer,
            SerialNumber = robot.RobotSerialNumber,
            OrderId = task.TaskCode,
            OrderUpdateId = 0,
            Nodes = new List<Node>(),
            Edges = new List<Edge>()
        };

        if (task.BeginLocation?.MapNode != null)
        {
            order.Nodes.Add(new Node
            {
                NodeId = task.BeginLocation.MapNode.NodeCode,
                SequenceId = 0,
                Released = true
            });
        }

        if (task.EndLocation?.MapNode != null)
        {
            order.Nodes.Add(new Node
            {
                NodeId = task.EndLocation.MapNode.NodeCode,
                SequenceId = 2,
                Released = true
            });

            if (task.BeginLocation?.MapNode != null)
            {
                order.Edges.Add(new Edge
                {
                    EdgeId = $"{task.BeginLocation.MapNode.NodeCode}_{task.EndLocation.MapNode.NodeCode}",
                    SequenceId = 1,
                    StartNodeId = task.BeginLocation.MapNode.NodeCode,
                    EndNodeId = task.EndLocation.MapNode.NodeCode,
                    Released = true
                });
            }
        }

        return order;
    }

    /// <summary>
    /// 创建即时动作消息
    /// </summary>
    private InstantAction CreateInstantAction(Robot robot, string actionType)
    {
        var action = new Domain.Models.VDA5050.Action
        {
            ActionId = Guid.NewGuid().ToString(),
            ActionType = actionType,
            BlockingType = "HARD"
        };

        return new InstantAction(
            (int)robot.HeaderId + 1,
            robot.ProtocolVersion,
            robot.RobotManufacturer,
            robot.RobotSerialNumber,
            new List<Domain.Models.VDA5050.Action> { action });
    }
}