CustomProtocolService.cs 7.65 KB
using Microsoft.Extensions.Logging;
using Rcs.Application.Common;
using Rcs.Application.Services;
using Rcs.Application.Services.Protocol;
using Rcs.Cyaninetech.Services;
using Rcs.Domain.Entities;
using Rcs.Domain.Extensions;
using Rcs.Domain.Models.VDA5050;

namespace Rcs.Infrastructure.Services.Protocol;

/// <summary>
/// 自定义协议服务实现
/// 通过LanYin服务与机器人通信
/// @author zzy
/// </summary>
public class CustomProtocolService : IProtocolService
{
    private readonly ILogger<CustomProtocolService> _logger;
    private readonly ILanYinService _lanYinService;
    private readonly IUnifiedTrafficControlService _unifiedTrafficControlService;

    public CustomProtocolService(
        ILogger<CustomProtocolService> logger,
        ILanYinService lanYinService,
        IUnifiedTrafficControlService unifiedTrafficControlService)
    {
        _logger = logger;
        _lanYinService = lanYinService;
        _unifiedTrafficControlService = unifiedTrafficControlService;
    }

    /// <summary>
    /// 支持的协议类型:自定义协议
    /// </summary>
    public ProtocolType ProtocolType => ProtocolType.Custom;

    /// <summary>
    /// 发送订单指令
    /// </summary>
    public async Task<ApiResponse> SendOrderAsync(Robot robot, RobotTask task, CancellationToken ct = default)
    {
        var areaCode = task.EndLocation?.StorageArea?.AreaCode;
        if (string.IsNullOrEmpty(areaCode))
        {
            return ApiResponse.Failed($"CustomProtocol - 未找到库区编码,任务: {task.TaskCode}");
        }

        var locationCode = task.BeginLocation?.LocationCode;
        if (string.IsNullOrEmpty(locationCode))
        {
            return ApiResponse.Failed($"CustomProtocol - 未找到起始库位编码,任务: {task.TaskCode}");
        }
        var request = new Rcs.Cyaninetech.Models.LanYinDispatchTaskRequest
        {
            location_id = locationCode,
            area = areaCode
        };

        var res = await _lanYinService.DispatchTaskAsync(request, ct);
        if (res.Success)
        {
            if (!string.IsNullOrEmpty(res.Data.RunningId))
            {
                task.Relation = res.Data.RunningId;
            }
            return ApiResponse.Successful();
        }
        return ApiResponse.Failed($"发送任务失败:: {res.Message},{res.Data}");
        
    }

    /// <summary>
    /// 取消指定订单
    /// </summary>
    public async Task CancelOrderAsync(Robot robot, string? orderId, CancellationToken ct = default)
    {
        _logger.LogInformation("CustomProtocol - 取消订单,机器人: {SerialNumber}, 订单: {OrderId}",
            robot.RobotSerialNumber, orderId);

        var result = await _lanYinService.CancelTaskByRobotAsync(robot.RobotSerialNumber, ct);
        if (!result.Success)
        {
            _logger.LogError($"取消订单失败: {result.Message}");
        }
    }

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

        var result = await _lanYinService.CancelTaskByRobotAsync(robot.RobotSerialNumber, ct);
        await ConfirmExceptionAsync(robot, ct);
        if (!result.Success)
        {
            _logger.LogError($"取消任务失败: {result.Message}");
        }

        // 释放该机器人的所有路径锁
        // @author zzy
        // @date 2026-01-30
        var releasedLockCount = await _unifiedTrafficControlService.ReleaseAllRobotLocksAsync(robot.RobotId);
        _logger.LogInformation("CustomProtocol - 任务取消,释放机器人路径锁: RobotId={RobotId}, ReleasedCount={Count}",
            robot.RobotId, releasedLockCount);
    }

    /// <summary>
    /// 发送即时动作指令(自定义协议暂不支持)
    /// </summary>
    public Task SendInstantActionAsync(Robot robot, InstantAction actions, CancellationToken ct = default)
    {
        _logger.LogWarning("自定义协议暂不支持发送InstantAction指令,机器人: {SerialNumber}", robot.RobotSerialNumber);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 复位机器人
    /// </summary>
    public async Task ResetRobotAsync(Robot robot, CancellationToken ct = default)
    {
        _logger.LogInformation("CustomProtocol - 复位机器人: {SerialNumber}", robot.RobotSerialNumber);

        var result = await _lanYinService.ResetRobotAsync(robot.RobotSerialNumber, ct);
        await ConfirmExceptionAsync(robot, ct);
        if (!result.Success)
        {
            _logger.LogError($"复位机器人失败: {result.Message}");
        }
    }

    /// <summary>
    /// 确认异常
    /// </summary>
    public async Task ConfirmExceptionAsync(Robot robot, CancellationToken ct = default)
    {
        _logger.LogInformation("CustomProtocol - 确认异常,机器人: {SerialNumber}", robot.RobotSerialNumber);

        var result = await _lanYinService.ConfirmExceptionAsync(robot.RobotSerialNumber, ct);
        if (!result.Success)
        {
            _logger.LogError($"确认异常失败: {result.Message}");
        }
    }

    public async Task RobotPauseAsync(Robot robot, CancellationToken ct = default)
    {
        _logger.LogInformation("CustomProtocol - 暂停,机器人: {SerialNumber}", robot.RobotSerialNumber);

        var result = await _lanYinService.PauseRobotAsync(robot.RobotSerialNumber, ct);
        if (!result.Success)
        {
            _logger.LogError($"机器人暂停失败: {result.Message}");
        }
    }

    public async Task RobotUnPauseAsync(Robot robot, CancellationToken ct = default)
    {
        _logger.LogInformation("CustomProtocol - 取消暂停,机器人: {SerialNumber}", robot.RobotSerialNumber);

        var result = await _lanYinService.UnPauseRobotAsync(robot.RobotSerialNumber, ct);
        if (!result.Success)
        {
            _logger.LogError($"机器人取消暂停失败: {result.Message}");
        }
    }

    public async Task<ApiResponse> ReLocationAsync(Robot robot,string mapCode, double x, double y, double theta, CancellationToken ct = default)
    {
        var result = await _lanYinService.RelocateRobotAsync(robot.RobotSerialNumber,Convert.ToInt32(mapCode),x,y,theta, ct);
        if (!result.Success)
        {
            _logger.LogError($"机器人重定位失败: {result.Message}");
            return ApiResponse.Failed($"机器人重定位失败: {result.Message}");
        }
        return ApiResponse.Successful();
    }

    /// <summary>
    /// 发送下一段路径指令(自定义协议暂不支持分段下发)
    /// </summary>
    /// <param name="robot">机器人实体</param>
    /// <param name="task">任务实体</param>
    /// <param name="ct">取消令牌</param>
    /// <returns>操作响应</returns>
    public Task<ApiResponse> SendNextSegmentAsync(Robot robot, RobotSubTask currentSubTask, CancellationToken ct = default, bool reExec = false)
    {
        _logger.LogWarning("自定义协议暂不支持分段下发下一段路径指令,机器人: {SerialNumber}, 任务: {TaskCode}",
            robot.RobotSerialNumber, currentSubTask.SubTaskId);
        return Task.FromResult(ApiResponse.Failed("自定义协议暂不支持分段下发功能"));
    }

    public Task<ApiResponse> SendNextSegmentAsync(string robotManufacturer, string robotSerialNumber, CancellationToken ct = default, bool reExec = false)
    {
        return Task.FromResult(ApiResponse.Failed("自定义协议暂不支持分段下发功能"));
    }
}