using Common;
using Common.Models;
using CommunityToolkit.Mvvm.Messaging;
using MegaRobo.C00225155.ControlDevices;
using MegaRobo.C00225155.ControlDevices.WeightDevice;
using MegaRobo.C00225155.Entities;
using MegaRobo.C00225155.Entities.Entity_DB;
using MegaRobo.Contract;
using MegaRobo.Contract.Abstractions;
using MegaRobo.ControlDevices;
using MegaRobo.Entities;
using MegaRobo.Logger;
using MegaRobo.PipetteTool.HamiltonConsole.PipetteDevices.HamiltonDevices;
using Microsoft.VisualBasic;
using NetTaste;
using Newtonsoft.Json.Linq;
using Nito.AsyncEx;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Policy;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Xml.Serialization;

namespace MegaRobo.C00225155.AppServer.ExecuteWorks
{
    /// <summary>
    /// 这里主要写配置工站上位机和PLC通讯的函数
    /// </summary>
    public partial class StationService_MaterialDosing : StationServiceBase
    {
        //    /// <summary>
        //    /// 下工装---等待信号的锁
        //    /// </summary>
        //    private static readonly AsyncLock _lockWaitSignal_Dnload = new AsyncLock();
        //    /// <summary>
        //    /// 上工装---等待信号的锁
        //    /// </summary>
        //    private static readonly AsyncLock _lockWaitSignal_Upload = new AsyncLock();
        //    /// <summary>
        //    /// 四轴机械手---等待信号的锁
        //    /// </summary>
        //    private static readonly AsyncLock _lockWaitSignal_FourAxis = new AsyncLock();

        //    /// <summary>
        //    /// 粉末原液瓶---等待信号的锁
        //    /// </summary>
        //    private static readonly AsyncLock _lockWaitSignal_Powder = new AsyncLock();

        //    /// <summary>
        //    /// 六轴机械手下反应瓶工装线程的信号锁，防止多线程同时操作
        //    /// </summary>
        //    private static readonly AsyncLock _lockBoxDn_SixAxis = new AsyncLock();
        //    /// <summary>
        //    /// 六轴机械手上反应瓶缓存工装线程的信号锁，防止多线程同时操作
        //    /// </summary>
        //    private static readonly AsyncLock _lockBoxUp_SixAxis = new AsyncLock();

        //    /// <summary>
        //    /// 冷却平台 是否有瓶子 更新属性的锁
        //    /// </summary>
        //    private static readonly SemaphoreSlim _lockColdStateTrace = new SemaphoreSlim(1, 1);
        //    /// <summary>
        //    /// 磁力搅拌 是否有瓶子 更新属性的锁
        //    /// </summary>
        //    private static readonly SemaphoreSlim _lockMagneticStirStateTrace = new SemaphoreSlim(1, 1);

        #region  PLC点位写/读
        /// <summary>
        /// 下料
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public async Task<ushort> ReadScannedValueAsync_Dnload(ushort address)
        {
            await Task.Delay(0);
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                return this.ModbusClient.Command.ReadValue<ushort>(address);
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站读取PLC信号异常",
                    Content = $"ReadScannedValueAsync_Dnload读取 {address} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"ReadScannedValueAsync_Dnload读取 {address} 时发生错误: {ex.Message}");
            }
            return 0;
        }

        /// <summary>
        /// 上料
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public async Task<ushort> ReadScannedValueAsync_Upload(ushort address)
        {
            await Task.Delay(0);
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                return this.ModbusClient.Command.ReadValue<ushort>(address);
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站读取PLC信号异常",
                    Content = $"ReadScannedValueAsync_Upload读取 {address} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"ReadScannedValueAsync_Upload读取 {address} 时发生错误: {ex.Message}");
            }
            return 0;
        }

        public async Task<ushort> ReadScannedValueAsync_FourAxis(ushort address)
        {
            await Task.Delay(0);
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                return this.ModbusClient.Command.ReadValue<ushort>(address);
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站读取PLC信号异常",
                    Content = $"ReadSixAxis读取 {address} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"ReadScannedValueAsync_SixAxis读取 {address} 时发生错误: {ex.Message}");
            }
            return 0;
        }

        public async Task<ushort> ReadScannedValueAsync_XZ(ushort address)
        {
            await Task.Delay(0);
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                return this.ModbusClient.Command.ReadValue<ushort>(address);
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站读取PLC信号异常",
                    Content = $"ReadPowder读取 {address} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"ReadScannedValueAsync_Powder读取 {address} 时发生错误: {ex.Message}");
            }
            return 0;
        }

        public async Task WriteCommandAsync_Dnload(ushort address, ushort value)
        {
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                this.ModbusClient.Command.WriteValue<ushort>(address, value);
                //await Task.Delay(30);
                while (await ReadScannedValueAsync_Dnload(address) != value)
                {
                    this.ModbusClient.Command.WriteValue<ushort>(address, value);
                    await Task.Delay(30);
                }
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站写入PLC信号异常",
                    Content = $"WriteDnload写入 {address}值{value} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"WriteCommandAsync_Dnload写入 {address}值{value} 时发生错误: {ex.Message}");
                return;
            }
        }

        public async Task WriteCommandAsync_Upload(ushort address, ushort value)
        {
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                this.ModbusClient.Command.WriteValue<ushort>(address, value);
                //await Task.Delay(30);
                while (await ReadScannedValueAsync_Upload(address) != value)
                {
                    this.ModbusClient.Command.WriteValue<ushort>(address, value);
                    await Task.Delay(30);

                }
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站写入PLC信号异常",
                    Content = $"WriteUpload写入 {address}值{value} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"WriteCommandAsync_Upload写入 {address}值{value} 时发生错误: {ex.Message}");
                return;
            }
        }


        public async Task WriteCommandAsync_FourAxis(ushort address, ushort value)
        {
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                this.ModbusClient.Command.WriteValue<ushort>(address, value);
                //await Task.Delay(30);
                while (await ReadScannedValueAsync_FourAxis(address) != value)
                {
                    this.ModbusClient.Command.WriteValue<ushort>(address, value);
                    await Task.Delay(30);
                }
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站写入PLC信号异常",
                    Content = $"WriteFourAxis写入 {address}值{value} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"WriteCommandAsync_FourAxis写入 {address}值{value} 时发生错误: {ex.Message}");
                return;
            }
        }

        public async Task WriteCommandAsync_XZ(ushort address, ushort value)
        {
            this.StationProp.ManualResetEvent.WaitOne(); //暂停标志
            try
            {
                this.ModbusClient.Command.WriteValue<ushort>(address, value);
                //await Task.Delay(30);
                while (await ReadScannedValueAsync_XZ(address) != value)
                {
                    this.ModbusClient.Command.WriteValue<ushort>(address, value);
                    await Task.Delay(30);

                }
            }
            catch (Exception ex)
            {
                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                {
                    Header = $"投料站写入PLC信号异常",
                    Content = $"WritePowder写入 {address}值{value} 时发生错误: {ex.Message}",
                    OkButtonContent = "继续",
                    CancelButtonContent = "取消",
                });
                this.Logger.LogError($"WriteCommandAsync_Powder写入 {address}值{value} 时发生错误: {ex.Message}");
                return;
            }
        }

        public async Task WaitForActionFinishAsync_Dnload(ushort point, ushort waitValue, CancellationToken token)
        {
            //using (await _lockWaitSignal_Dnload.LockAsync(token))
            {
                try
                {

                    ushort result = 0;
                    do
                    {
                        token.ThrowIfCancellationRequested();
                        this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志
                        result = await ReadScannedValueAsync_Dnload(point);
                        await Task.Delay(100, token);
                    } while (result != waitValue && !token.IsCancellationRequested);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (Exception ex)
                {
                    WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                    {
                        Header = $"投料站等待PLC信号异常",
                        Content = $"WaitForDnload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}",
                        OkButtonContent = "继续",
                        CancelButtonContent = "取消",
                    });
                    this.Logger.LogError($"WaitForActionFinishAsync_Dnload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}");
                    return;
                }
            }
        }

        public async Task WaitForActionFinishAsync_Upload(ushort point, ushort waitValue, CancellationToken token)
        {
            //using (await _lockWaitSignal_Upload.LockAsync(token))
            {
                try
                {
                    ushort result = 0;
                    do
                    {
                        token.ThrowIfCancellationRequested();
                        this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志
                        result = await ReadScannedValueAsync_Upload(point);
                        await Task.Delay(100, token);
                    } while (result != waitValue && !token.IsCancellationRequested);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (Exception ex)
                {
                    WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                    {
                        Header = $"投料站等待PLC信号异常",
                        Content = $"WaitForUpload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}",
                        OkButtonContent = "继续",
                        CancelButtonContent = "取消",
                    });
                    this.Logger.LogError($"WaitForActionFinishAsync_Upload等待 {point}是否为{waitValue} 时发生错误: {ex.Message}");
                    return;
                }
            }
        }

        public async Task WaitForActionFinishAsync_FourAxis(ushort point, ushort waitValue, CancellationToken cancellationToken)
        {
            //using (await _lockWaitSignal_FourAxis.LockAsync(cancellationToken))
            {
                try
                {
                    ushort result = 0;
                    do
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志
                        result = await ReadScannedValueAsync_FourAxis(point);
                        await Task.Delay(100, cancellationToken);
                    } while (result != waitValue && !cancellationToken.IsCancellationRequested);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (Exception ex)
                {
                    WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                    {
                        Header = $"投料站等待PLC信号异常",
                        Content = $"WaitForFourAxis等待 {point}是否为{waitValue} 时发生错误: {ex.Message}",
                        OkButtonContent = "继续",
                        CancelButtonContent = "取消",
                    });
                    this.Logger.LogError($"WaitForActionFinishAsync_FourAxis等待 {point}是否为{waitValue} 时发生错误: {ex.Message}");
                    return;
                }
            }
        }

        public async Task WaitForActionFinishAsync_XZ(ushort point, ushort waitValue, CancellationToken cancellationToken)
        {
            //using (await _lockWaitSignal_Powder.LockAsync(cancellationToken))
            {
                try
                {
                    ushort result = 0;
                    do
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                        this.StationProp.ManualResetEvent.WaitOne(); // 暂停标志
                        result = await ReadScannedValueAsync_XZ(point);
                        await Task.Delay(100, cancellationToken);
                    } while (result != waitValue && !cancellationToken.IsCancellationRequested);
                }
                catch (OperationCanceledException)
                {
                    return;
                }
                catch (Exception ex)
                {
                    WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                    {
                        Header = $"投料站等待PLC信号异常",
                        Content = $"WaitForPowder等待 {point}是否为{waitValue} 时发生错误: {ex.Message}",
                        OkButtonContent = "继续",
                        CancelButtonContent = "取消",
                    });
                    this.Logger.LogError($"WaitForActionFinishAsync_Powder等待 {point}是否为{waitValue} 时发生错误: {ex.Message}");
                    return;
                }
            }
        }
        #endregion

        #region 传送平台

        /// <summary>
        /// 传送平台到过渡舱外准备上载具
        /// </summary>
        /// <param name="reactBottleModel"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task TransferUploadBox(CancellationToken token)
        {
            if (token.IsCancellationRequested) return;
            //传送平台到过渡舱外
            await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 1);

            await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 22, token);
            //清除信号
            await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 0);
            //await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 0, token);
            await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 5, token); //等待PLC 准备就绪 等待空闲中
        }

        /// <summary>
        /// 传送平台到手套箱内部
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task TransferToDeviceInner(CancellationToken token)
        {
            if (token.IsCancellationRequested) return;
            //传送平台到手套箱内部
            await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 3);

            await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 22, token);
            //清除信号
            await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_TransferPlate_TaskNo, 0);

            await WaitForActionFinishAsync_Upload(PlcPoints_MaterialDose.R_TransferPlate_RunResult, 5, token); //等待PLC 准备就绪 等待空闲中
        }

        #endregion

        #region 四轴机械手
        /// <summary>
        /// 四轴机械手取托盘
        /// </summary>
        /// <param name="aimarea">目标区域编号</param>
        /// <param name="boxType">托盘类型</param>
        /// <param name="pos">目标托盘位置号</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisTakeBox(ushort aimarea, BoxTypeEnum boxType, ushort pos, CancellationToken token)
        {
            ///// 目标区域
            ///// 1：手套箱传送平台； 2：Tip托盘存放平台；12：托盘存放平台；
            ///// </summary>
            //public readonly static ushort W_Robot_AimArea = 2202;
            ///// <summary>
            ///// 目标托盘位置号
            ///// </summary>
            //public readonly static ushort W_Robot_AimAreaBoxPosid = 2203;
            ///// <summary>
            ///// 托盘类型：1:40mL瓶; 2:12mL瓶; 3:5mL瓶; 4:TIP头;
            ///// </summary>
            //public readonly static ushort W_Robot_BoxType = 2204;


            if (token.IsCancellationRequested || TestMode) return;
            ushort fixtureType = 0;
            switch (boxType)
            {
                case BoxTypeEnum._40mL原液工装:
                    fixtureType = 1;
                    break;
                case BoxTypeEnum._12mL样品工装:
                    fixtureType = 2;
                    break;
                case BoxTypeEnum._5mL样品工装:
                    fixtureType = 3;
                    break;
                case BoxTypeEnum._50uLTip头工装:
                    fixtureType = 4;
                    break;
                case BoxTypeEnum._300uLTip头工装:
                    fixtureType = 4;
                    break;
                case BoxTypeEnum._1000uLTip头工装:
                    fixtureType = 4;
                    break;
            }

            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, pos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, fixtureType);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 11);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴机械手放托盘
        /// </summary>
        /// <param name="aimarea">目标区域编号</param>
        /// <param name="boxType">托盘类型</param>
        /// <param name="pos">目标托盘位置号</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisPutBox(ushort aimarea, BoxTypeEnum boxType, ushort pos, CancellationToken token)
        {
            ///// 目标区域
            ///// 1：手套箱传送平台； 2：Tip托盘存放平台；12：托盘存放平台；
            ///// </summary>
            //public readonly static ushort W_Robot_AimArea = 2202;
            ///// <summary>
            ///// 目标托盘位置号
            ///// </summary>
            //public readonly static ushort W_Robot_AimAreaBoxPosid = 2203;
            ///// <summary>
            ///// 托盘类型：1:40mL瓶; 2:12mL瓶; 3:5mL瓶; 4:TIP头;
            ///// </summary>
            //public readonly static ushort W_Robot_BoxType = 2204;


            if (token.IsCancellationRequested || TestMode) return;
            ushort fixtureType = 0;
            switch (boxType)
            {
                case BoxTypeEnum._40mL原液工装:
                    fixtureType = 1;
                    break;
                case BoxTypeEnum._12mL样品工装:
                    fixtureType = 2;
                    break;
                case BoxTypeEnum._5mL样品工装:
                    fixtureType = 3;
                    break;
                case BoxTypeEnum._50uLTip头工装:
                    fixtureType = 4;
                    break;
                case BoxTypeEnum._300uLTip头工装:
                    fixtureType = 4;
                    break;
                case BoxTypeEnum._1000uLTip头工装:
                    fixtureType = 4;
                    break;
            }

            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, pos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, fixtureType);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 12);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴机械手取粉末加样头
        /// </summary>
        /// <param name="aimarea">目标区域编号</param>
        /// <param name="aimarea_box">目标托盘号</param>
        /// <param name="bottlepos">目标位置号</param>
        /// <param name="powderbottletype">粉末类型</param>
        /// <param name="token"></param>
        /// <param name="point">plc点位，起始或终点是传递仓到缓存位的话，开始取最终放需要写1</param>
        /// <returns></returns>
        private async Task FourAxisTakePowderHeader(int aimarea, int aimarea_box, int bottlepos, PowderBottleTypeEnum powderbottletype, CancellationToken token, ushort point = 0)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, powderbottletype == PowderBottleTypeEnum._16mL ? (ushort)1 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, point);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 1);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴机械手放粉末加样头
        /// </summary>
        /// <param name="aimarea"></param>
        /// <param name="aimarea_box"></param>
        /// <param name="bottlepos"></param>
        /// <param name="powderbottletype"></param>
        /// <param name="token"></param>
        /// <param name="point">plc点位，起始或终点是传递仓到缓存位的话，开始取最终放需要写1</param>
        /// <returns></returns>
        private async Task FourAxisPutPowderHeader(int aimarea, int aimarea_box, int bottlepos, PowderBottleTypeEnum powderbottletype, CancellationToken token, ushort point = 0)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, powderbottletype == PowderBottleTypeEnum._16mL ? (ushort)1 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, point);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 2);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴运行到扫码位置
        /// </summary>
        /// <param name="liquidBottle">bottle : 1:40 2:12 3:5</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisGoToScannPos_liquid(CancellationToken token, int liquidBottle, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)liquidBottle);  
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 23);  //goto scan pos

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveScanPos, 1, token);

            string sn = await scannerService.ReadAsnyc(TimeSpan.FromSeconds(5));

            if (sourceLiquidBottle != null)
            {
                sourceLiquidBottle.SNCode = sn;
            }
            if (sampleBottle != null)
            {
                sampleBottle.SNCode = sn;
            }
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_ScanResult, 1);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveScanPos, 0, token);

            //清除信号
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_ScanResult, 0);
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴运行到粉末瓶扫码位置
        /// </summary>
        /// <param name="ispowder">是否是粉末瓶子</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisGoToScannPos_powder(CancellationToken token, SourcePowderBottleModel powderbottle)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 3);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveSideScanPos, 1, token);

            //触发扫码
            string snCode = await scannerService_Powder.ReadAsnyc(TimeSpan.FromSeconds(5));
            powderbottle.SNCode = snCode;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_SideScanResult, 1); //回复扫码完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArriveSideScanPos, 0, token);
            //清除信号
            await WriteCommandAsync_Upload(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_SideScanResult, 0);
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }


        private async Task<double> FourAxisPutPowderHeaderToPreWeight(CancellationToken token)
        {
            if (token.IsCancellationRequested || TestMode) return 16;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 4);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 2);

            //等待PLC回复到预称重位
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_ArrivePreWeightPos, 1, token);

            //这边需要称重并返回PLC完成
            double powderWeight = TestMode ? 16 : (await preWeight.ReadWeightValue());
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_PreWeightFinish, 1);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
            return powderWeight;
        }

        /// <summary>
        /// 四轴机械手拿液体瓶子
        /// </summary>
        /// <param name="aimarea">目标区域编号</param>
        /// <param name="aimarea_box">目标托盘位置号</param>
        /// <param name="bottlepos">目标孔编号</param>
        /// <param name="powderbottletype">瓶类型</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisTakeLiquidBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SourceLiquidBottleModel sourceLiquidBottle)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 1);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sourceLiquidBottle.LiquidBottleLidState == SourceBottleLidStateEnum.Close ? (ushort)1 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 21);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴机械手放液体瓶子
        /// </summary>
        /// <param name="aimarea">目标区域编号</param>
        /// <param name="aimarea_box">目标托盘位置号</param>
        /// <param name="bottlepos">目标孔编号</param>
        /// <param name="powderbottletype">瓶类型</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisPutLiquidBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SourceLiquidBottleModel sourceLiquidBottle)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 1);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sourceLiquidBottle.LiquidBottleLidState == SourceBottleLidStateEnum.Close ? (ushort)1 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 22);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴机械手取样品瓶子
        /// </summary>
        /// <param name="aimarea">目标区域编号</param>
        /// <param name="aimarea_box">目标托盘位置号</param>
        /// <param name="bottlepos">目标孔编号</param>
        /// <param name="powderbottletype">瓶类型</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisTakeSampleBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SampleBottleModel sampleBottle)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, sampleBottle.SampleBottleType == SampleBottleTypeEnum._5mL ? (ushort)3 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sampleBottle.SampleBottleLidState == SampleBottleLidStateEnum.Close ? (ushort)1 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 21);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }

        /// <summary>
        /// 四轴机械手放样品瓶子
        /// </summary>
        /// <param name="aimarea">目标区域编号</param>
        /// <param name="aimarea_box">目标托盘位置号</param>
        /// <param name="bottlepos">目标孔编号</param>
        /// <param name="powderbottletype">瓶类型</param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task FourAxisPutSampleBottle(CancellationToken token, int aimarea, int aimarea_box, int bottlepos, SampleBottleModel sampleBottle)
        {
            if (token.IsCancellationRequested || TestMode) return;
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, (ushort)aimarea);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, (ushort)aimarea_box);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, (ushort)bottlepos);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, sampleBottle.SampleBottleType == SampleBottleTypeEnum._5mL ? (ushort)3 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, sampleBottle.SampleBottleLidState == SampleBottleLidStateEnum.Close ? (ushort)1 : (ushort)2);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 22);

            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param1, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param2, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param3, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param4, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_Param5, 0);
            await WriteCommandAsync_FourAxis(PlcPoints_MaterialDose.W_Robot_TaskNo, 0);

            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_Robot_RunResult, 5, token);
        }
        #endregion

        #region XZ模组
        /// <summary>
        /// 假盖子开关盖
        /// </summary>
        /// <param name="token"></param>
        /// <param name="isOpen"></param>
        /// <param name="sourceLiquidBottle"></param>
        /// <param name="sampleBottle"></param>
        /// <returns></returns>
        private async Task OpenCloseBottleFakeCap(CancellationToken token,bool isOpen, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null)
        {
            if (token.IsCancellationRequested || TestMode) return;
            int bottletype = 0;
            if (sourceLiquidBottle != null)
            {
                bottletype = 1;
            }
            if (sampleBottle != null)
            {
                if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL)
                {
                    bottletype = 2;
                }
                else
                {
                    bottletype = 3;
                }
            }
            ushort taskNo = isOpen ? (ushort)1 : (ushort)2;
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)2);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, taskNo);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);
            if (sourceLiquidBottle != null)
            {
                sourceLiquidBottle.LiquidBottleLidState = isOpen ?  SourceBottleLidStateEnum.Open : SourceBottleLidStateEnum.Close;
            }
            if (sampleBottle != null)
            {
                sampleBottle.SampleBottleLidState = isOpen ?  SampleBottleLidStateEnum.Open : SampleBottleLidStateEnum.Close;
            }

            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);
        }

        /// <summary>
        /// XZ模组开盖
        /// </summary>
        /// <param name="token"></param>
        /// <param name="sourceLiquidBottle"></param>
        /// <param name="sampleBottle"></param>
        /// <returns></returns>
        private async Task OpenBottleLid(CancellationToken token, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null)
        {
            if (token.IsCancellationRequested || TestMode) return;
            int bottletype = 0;
            if (sourceLiquidBottle != null)
            {
                bottletype = 1;
            }
            if (sampleBottle != null)
            {
                if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL)
                {
                    bottletype = 2;
                }
                else
                {
                    bottletype = 3;
                }
            }
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)1);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 1);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);
            if (sourceLiquidBottle != null)
            {
                sourceLiquidBottle.LiquidBottleLidState = SourceBottleLidStateEnum.Open;
            }
            if (sampleBottle != null)
            {
                sampleBottle.SampleBottleLidState = SampleBottleLidStateEnum.Open;
            }

            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);
        }

        /// <summary>
        /// XZ模组关盖
        /// </summary>
        /// <param name="token"></param>
        /// <param name="sourceLiquidBottle"></param>
        /// <param name="sampleBottle"></param>
        /// <returns></returns>
        private async Task CloseBottleLid(CancellationToken token, SourceLiquidBottleModel sourceLiquidBottle = null, SampleBottleModel sampleBottle = null)
        {
            if (token.IsCancellationRequested || TestMode) return;
            int bottletype = 0;
            if (sourceLiquidBottle != null)
            {
                bottletype = 1;
            }
            if (sampleBottle != null)
            {
                if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL)
                {
                    bottletype = 2;
                }
                else
                {
                    bottletype = 3;
                }
            }
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)1);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 2);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);
            if (sourceLiquidBottle != null)
            {
                sourceLiquidBottle.LiquidBottleLidState = SourceBottleLidStateEnum.Close;
            }
            if (sampleBottle != null)
            {
                sampleBottle.SampleBottleLidState = SampleBottleLidStateEnum.Close;
            }
            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);
        }

        /// <summary>
        /// XZ摇匀
        /// </summary>
        /// <param name="token"></param>
        /// <param name="sampleBottle"></param>
        /// <returns></returns>
        private async Task ShakeSampleBottle(CancellationToken token, SampleBottleModel sampleBottle)
        {
            if (token.IsCancellationRequested || TestMode) return;
            int bottletype = 0;

            if (sampleBottle != null)
            {
                if (sampleBottle.SampleBottleType == SampleBottleTypeEnum._12mL)
                {
                    bottletype = 2;
                }
                else
                {
                    bottletype = 3;
                }
            }
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, (ushort)bottletype);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)10);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 3);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);
            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);

            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);
        }

        //public async Task TestSuckVolume(CancellationToken token, double targetVolume,bool isFirst)
        //{
        //    SourceLiquidBottleModel sourceLiquidBottleModel = new SourceLiquidBottleModel()
        //    {
        //        LiquidBottleLidState = SourceBottleLidStateEnum.Close
        //    };

        //    if (isFirst)
        //    {
        //        await FourAxisTakeLiquidBottle(_cts.Token, (int)BoxAreaEnum._托盘存放平台, 1, 1, sourceLiquidBottleModel);
        //        await FourAxisPutLiquidBottle(_cts.Token, (int)BoxAreaEnum._开关盖区域, 0, 0, sourceLiquidBottleModel);
        //        await OpenBottleLid(_cts.Token, sourceLiquidBottleModel, null);
        //    }
        //    else
        //    {
        //        await CloseBottleLid(_cts.Token, sourceLiquidBottleModel, null);
        //        await FourAxisTakeLiquidBottle(_cts.Token, (int)BoxAreaEnum._开关盖区域, 0, 0, sourceLiquidBottleModel);
        //        await FourAxisPutLiquidBottle(_cts.Token, (int)BoxAreaEnum._托盘存放平台, 1, 1, sourceLiquidBottleModel);
        //    }
        //    List<(int tipVolume, List<double> countlists)> selectedTips = new List<(int tipVolume, List<double> countlists)>();
        //    (int tipVolume, List<double> countlists) selectedTip = (50,new List<double>() { 30});
        //    selectedTips.Add(selectedTip);
        //    for (int i = 0; i < selectedTips.Count; i++)
        //    {
        //        TipTypeEnum tipType = TipTypeEnum._1000UL;
        //        DeviceNames deviceName = DeviceNames.Pipette_Dose_1ml_1;
        //        if (selectedTips[i].tipVolume == 1000)
        //        {
        //            tipType = TipTypeEnum._1000UL; deviceName = DeviceNames.Pipette_Dose_1ml_1;
        //        }
        //        else if (selectedTips[i].tipVolume == 300)
        //        {
        //            tipType = TipTypeEnum._300UL; deviceName = DeviceNames.Pipette_Dose_1ml_2;
        //        }
        //        else if (selectedTips[i].tipVolume == 50)
        //        {
        //            tipType = TipTypeEnum._50UL; deviceName = DeviceNames.Pipette_Dose_1ml_3;
        //        }
        //        this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Ongoing) { Tag = "使用中" });
        //        while (true)
        //        {
        //            List<TipBoxModel> targetTipBoxes = workService.ProjectPro.TipHeadArea.Where(tipBox => (tipBox.TipType == tipType) && tipBox.TipItems != null && tipBox.TipItems.Any(item => item.IsAvailable)).ToList();
        //            //告诉PLC到取Tip头位置
        //            if (targetTipBoxes == null)
        //            {
        //                WeakReferenceMessenger.Default.Send(new ConfirmMessage()
        //                {
        //                    Header = $"取Tip失败",
        //                    Content = $"没有tip了！！！",
        //                    OkButtonContent = "继续",
        //                    CancelButtonContent = "取消",
        //                });
        //                continue;
        //            }
        //            if (isFirst)
        //            {
        //                await PipetteTakeTip(token, targetTipBoxes.FirstOrDefault(), deviceName);
        //                //取Tip
        //                var restip = await GunPickUpTip_M1(deviceName, pipetteService_1ml, tipType);
        //                if (restip)
        //                {
        //                    break;
        //                }
        //            }
        //            else
        //            {
        //                await PipetteDiscardTip(token, deviceName);
        //                await GunDiscardTip_M1(deviceName, pipetteService_1ml);
        //                return;
        //            }
        //        }
        //        for (int j = 0; j < selectedTips[i].countlists.Count; j++)//用这种枪头要吸液排液多少次
        //        {
        //            //告诉PLC到吸液位置
        //            await PipetteAbsorb(token, deviceName);
        //        }
        //        //告诉PLC到丢弃Tip头位置
        //        //await PipetteDiscardTip(token, deviceName);
        //        //await GunDiscardTip_M1(deviceName, pipetteService_1ml);
        //        //this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Done));
        //    }
        //}

        private async Task XZ_TakeTip_Absorb_Dispense_DiscardTip(CancellationToken token, string sourceliquidname, double targetVolume, SourceLiquidBottleModel sourceLiquidBottleModel, SampleBottleModel sampleBottleModel)
        {
            if (TestMode) return;
            List<(int tipVolume, List<double> countlists)> selectedTips = new List<(int tipVolume, List<double> countlists)>();
            selectedTips = SelectTipsEx(targetVolume);
            
            for (int i = 0; i < selectedTips.Count; i++)
            {
                TipTypeEnum tipType = TipTypeEnum._1000UL;
                DeviceNames deviceName = DeviceNames.Pipette_Dose_1ml_1;
                if (selectedTips[i].tipVolume == 1000)
                {
                    tipType = TipTypeEnum._1000UL; deviceName = DeviceNames.Pipette_Dose_1ml_1;
                }
                else if (selectedTips[i].tipVolume == 300)
                {
                    tipType = TipTypeEnum._300UL; deviceName = DeviceNames.Pipette_Dose_1ml_2;
                }
                else if (selectedTips[i].tipVolume == 50)
                {
                    tipType = TipTypeEnum._50UL; deviceName = DeviceNames.Pipette_Dose_1ml_3;
                }
                this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Ongoing) { Tag = "使用中" });
                while (true)
                {
                    List<TipBoxModel> targetTipBoxes = workService.ProjectPro.TipHeadArea.Where(tipBox => (tipBox.TipType == tipType) && tipBox.TipItems != null && tipBox.TipItems.Any(item => item.IsAvailable)).ToList();
                    //告诉PLC到取Tip头位置
                    if (targetTipBoxes == null)
                    {
                        WeakReferenceMessenger.Default.Send(new ConfirmMessage()
                        {
                            Header = $"取Tip失败",
                            Content = $"没有tip了！！！",
                            OkButtonContent = "继续",
                            CancelButtonContent = "取消",
                        });
                        continue;
                     }
                    await PipetteTakeTip(token, targetTipBoxes.FirstOrDefault(), deviceName);
                    //取Tip
                    var restip = await GunPickUpTip_M1(deviceName, pipetteService_1ml, tipType);
                    if (restip)
                    {
                        break;
                    }
                }

                for (int j = 0; j < selectedTips[i].countlists.Count; j++)//用这种枪头要吸液排液多少次
                {
                    //告诉PLC到吸液位置
                    await PipetteAbsorb(token, deviceName);
                    int bottletype = workService.ProjectPro.SampleBottleType == SampleBottleTypeEnum._12mL ? 1 : 2;
                    await GunAbsorb_M1(deviceName, pipetteService_1ml, sourceliquidname, (int)tipType, selectedTips[i].countlists[j] * 10,sourceLiquidBottleModel);
                    //告诉PLC到排液位置
                    await PipetteDispense(token, deviceName);
                    await GunDispensing_M1(deviceName, pipetteService_1ml, sourceliquidname, (int)tipType, (uint)(selectedTips[i].countlists[j] * 10), sampleBottleModel);
                }
                //告诉PLC到丢弃Tip头位置
                await PipetteDiscardTip(token,deviceName);
                await GunDiscardTip_M1(deviceName, pipetteService_1ml);
                this.OnWorkStatusChanged(new ControlWorkStatus(deviceName.ToString(), ExecuteStatus.Done));
            }
        }

        public async Task UpdateTipBox(TipBoxModel tipBoxModel)
        {
            var tipInStation = await dataAccessService.LoadEntityAsync<TipBoxModel>(t => t.BoxId_inDosingStation == tipBoxModel.BoxId_inDosingStation);
            if (tipInStation == null)
            {
                var tipaddres = await dataAccessService.AddEntityAsync(tipBoxModel);
            }
            else
            {
                await dataAccessService.UpdateEntityAsync(tipBoxModel);
            }
        }

        public List<(int tipVolume, List<double> absorbVolumnList)> SelectTipsEx(double targetVolumn)
        {
            List<(int tipVolume, List<double> absorbVolumnList)> selectedTips = new List<(int tipVolume, List<double> absorbVolumnList)>();
            bool has50Tip = workService.ProjectPro.TipHeadArea.Any(t => t.HaveBox && t.TipType == TipTypeEnum._50UL && t.TipItems.Any(ti => ti.IsAvailable));
            bool has300Tip = workService.ProjectPro.TipHeadArea.Any(t => t.HaveBox && t.TipType == TipTypeEnum._300UL && t.TipItems.Any(ti => ti.IsAvailable));
            bool has1000Tip = workService.ProjectPro.TipHeadArea.Any(t => t.HaveBox && t.TipType == TipTypeEnum._1000UL && t.TipItems.Any(ti => ti.IsAvailable));
            if (!has50Tip && !has300Tip && !has1000Tip) return selectedTips;
            TipTypeEnum tipType = TipTypeEnum._1000UL;
            if (targetVolumn <= 50)
            {
                tipType = has50Tip ? TipTypeEnum._50UL : (has300Tip ? TipTypeEnum._300UL : TipTypeEnum._1000UL); //优先50 30 1000
            }
            else if (targetVolumn <= 300)
            {
                tipType = has300Tip ? TipTypeEnum._300UL : (has1000Tip ? TipTypeEnum._1000UL : TipTypeEnum._50UL); //优先30 1000 50 
            }
            else
            {
                tipType = has1000Tip ? TipTypeEnum._1000UL : (has300Tip ? TipTypeEnum._300UL : TipTypeEnum._50UL); //优先1000 50 30 
            }

            (int tipVolume, List<double> absorbVolumnList) volumeInfo;
            volumeInfo.tipVolume = tipType == TipTypeEnum._50UL ? 50 : (tipType == TipTypeEnum._300UL ? 300 : 1000);
            volumeInfo.absorbVolumnList = new List<double>();
            while (targetVolumn > 0)
            {
                if (targetVolumn > volumeInfo.tipVolume)
                {
                    volumeInfo.absorbVolumnList.Add(volumeInfo.tipVolume);
                    targetVolumn -= volumeInfo.tipVolume;
                }
                else
                {
                    volumeInfo.absorbVolumnList.Add(targetVolumn);
                    targetVolumn = 0;
                }
            }
            selectedTips.Add(volumeInfo);
            return selectedTips;
        }

        /// <summary>
        /// 选择Tip头的函数
        /// </summary>
        /// <param name="targetVolumn"></param>
        /// <returns></returns>
        public List<(double tipVolume, List<double> absorbVolumnList)> SelectTips(double targetVolumn)
        {
            List<(double tipVolume, List<double> absorbVolumnList)> selectedTips = new List<(double tipVolume, List<double> absorbVolumnList)>();

            // 1. 查找「存在且有可用Tip头」的工装（判断是否有对应类型的Tip）
            TipBoxModel _1000ulTip = workService.ProjectPro.TipHeadArea.FirstOrDefault(tipBox =>
                tipBox.TipType == TipTypeEnum._1000UL &&
                tipBox.TipItems != null &&
                tipBox.TipItems.Any(item => item.IsAvailable));
            TipBoxModel _300ulTip = workService.ProjectPro.TipHeadArea.FirstOrDefault(tipBox =>
                tipBox.TipType == TipTypeEnum._300UL &&
                tipBox.TipItems != null &&
                tipBox.TipItems.Any(item => item.IsAvailable));
            TipBoxModel _50ulTip = workService.ProjectPro.TipHeadArea.FirstOrDefault(tipBox =>
                tipBox.TipType == TipTypeEnum._50UL &&
                tipBox.TipItems != null &&
                tipBox.TipItems.Any(item => item.IsAvailable));

            // 2. 整理「可用的Tip容量」（按「从大到小」排序，确保优先用大容量）
            var availableTipVolumes = new List<double>();
            if (_1000ulTip != null) availableTipVolumes.Add(1000); // 有1000UL Tip则加入
            if (_300ulTip != null) availableTipVolumes.Add(300);   // 有300UL Tip则加入
            if (_50ulTip != null) availableTipVolumes.Add(50);     // 有10UL Tip则加入

            // 无可用Tip时，直接返回空列表（可根据业务需求抛异常）
            if (!availableTipVolumes.Any())
            {
                //跟BS要Tip头
                return selectedTips;
            }

            // 3. 初始化剩余体积（保留3位小数，避免精度问题）
            double remainingVolume = Math.Round(targetVolumn, 3, MidpointRounding.ToPositiveInfinity);

            while (remainingVolume > 0) 
            {
                double currentVolumn = 0;
                double tipvolumn = 1000;
                if (remainingVolume > 1000)
                {
                    currentVolumn = 1000;
                    remainingVolume -= 1000;
                    tipvolumn = 1000;
                }
                else if (remainingVolume > 300)
                {
                    tipvolumn = 1000;
                    currentVolumn = remainingVolume;
                    remainingVolume = 0;
                }
                else if (remainingVolume > 50)
                {
                    tipvolumn = 300;
                    currentVolumn = remainingVolume;
                    remainingVolume = 0;
                }
                else
                {
                    tipvolumn = 50;
                    currentVolumn = remainingVolume;
                    remainingVolume = 0;
                }
                var st = selectedTips.FirstOrDefault(s => s.tipVolume == tipvolumn);
                if (st.tipVolume > 0)
                {
                    st.absorbVolumnList.Add(currentVolumn);
                }
                else
                {
                    List<double> absorbVolumes = new List<double>();
                    absorbVolumes.Add(currentVolumn);
                    selectedTips.Add((tipvolumn, absorbVolumes));
                }
                    
            }

            // 4. 优先用「最大可用Tip」处理剩余体积
            //foreach (var tipVolume in availableTipVolumes)
            //{
            //    if (remainingVolume <= 0) break; // 体积处理完则退出循环

            //    List<double> absorbVolumes = new List<double>();

            //    // 步骤1：用当前Tip处理「尽可能多的满容量体积」
            //    if (remainingVolume >= tipVolume)
            //    {
            //        int fullTipCount = (int)(remainingVolume / tipVolume); // 需要的满容量Tip数量
            //        absorbVolumes.AddRange(Enumerable.Repeat(tipVolume, fullTipCount)); // 记录满容量吸液
            //        remainingVolume -= tipVolume * fullTipCount; // 扣除已处理的体积
            //        remainingVolume = Math.Round(remainingVolume, 3, MidpointRounding.ToPositiveInfinity); // 重新校准精度
            //    }

            //    // 步骤2：处理「剩余的少量体积」（不足一个满容量Tip）
            //    if (remainingVolume > 0)
            //    {
            //        absorbVolumes.Add(remainingVolume); // 用当前Tip处理剩余体积
            //        remainingVolume = 0; // 体积处理完成
            //    }

            //    // 将当前Tip的选择结果加入列表
            //    selectedTips.Add((tipVolume, absorbVolumes));
            //}
            return selectedTips;
        }


        /// <summary>
        /// 移液枪取Tip头
        /// </summary>
        /// <param name="token"></param>
        /// <param name="tipType"></param>
        /// <returns></returns>
        private async Task PipetteTakeTip(CancellationToken token, TipBoxModel tipBox, DeviceNames deviceName)
        {
            if (token.IsCancellationRequested || TestMode) return;
            ushort pipteId = 1;
            if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4)
            {
                pipteId = (ushort)((int)deviceName - 6);
            }
            TipHeadItem tipHead = tipBox.TipItems.FirstOrDefault(f => f.IsAvailable);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId);  //移液枪编号 1-4
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, (ushort)(3 - tipBox.BoxId_inDosingStation + 1));//(ushort)tipBox.BoxId_inDosingStation);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param3, (ushort)tipHead.UseIndex);//
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 11);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);

            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param2, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param3, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);
            tipHead.IsAvailable = false;

            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);

        }

        /// <summary>
        /// 移液枪吸液
        /// </summary>
        /// <param name="token"></param>
        /// <param name="tipType"></param>
        /// <returns></returns>
        private async Task PipetteAbsorb(CancellationToken token, DeviceNames deviceName)
        {
            if (token.IsCancellationRequested || TestMode) return;
            ushort pipteId = 1;
            if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4)
            {
                pipteId = (ushort)((int)deviceName - 6);
            }
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId);  //移液枪编号 1-4
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 12);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);

            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);

            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);
        }

        /// <summary>
        /// 移液枪分液
        /// </summary>
        /// <param name="token"></param>
        /// <param name="tipType"></param>
        /// <returns></returns>
        private async Task PipetteDispense(CancellationToken token, DeviceNames deviceName)
        {
            if (token.IsCancellationRequested || TestMode) return;
            ushort pipteId = 1;
            if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4)
            {
                pipteId = (ushort)((int)deviceName - 6);
            }
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId);  //移液枪编号 1-4
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 13);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);

            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);

            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);
        }

        /// <summary>
        /// 移液枪丢弃Tip头
        /// </summary>
        /// <param name="token"></param>
        /// <param name="tipType"></param>
        /// <returns></returns>
        private async Task PipetteDiscardTip(CancellationToken token, DeviceNames deviceName)
        {
            if (token.IsCancellationRequested || TestMode) return;
            ushort pipteId = 1;
            if (deviceName >= DeviceNames.Pipette_Dose_1ml_1 && deviceName <= DeviceNames.Pipette_Dose_1ml_4)
            {
                pipteId = (ushort)((int)deviceName - 6);
            }
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, pipteId);  //移液枪编号 1-4
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 14);
            //等待PLC回复执行完成
            await WaitForActionFinishAsync_FourAxis(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 22, token);

            //信号清零
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_Param1, 0);
            await WriteCommandAsync_XZ(PlcPoints_MaterialDose.W_BottleLidAndPipette_TaskNo, 0);

            await WaitForActionFinishAsync_XZ(PlcPoints_MaterialDose.R_BottleLidAndPipette_RunResult, 5, token);
        }
        #endregion



        private async Task RefreshReactBottleState(int boxId, int posId, SampleBottleStateEnum state)
        {

            await Task.Delay(0);
        }


    }
}
