using ExternalCalibration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Xml.Linq;
using Testrong.Core.Common;
using Testrong.Core.Model.ACTiming;
using Testrong.Core.Model.ChannelMap;
using Testrong.Core.Model.Dps;
using Testrong.Core.Model.Enums;
using Testrong.Core.Model.Pattern;
using Testrong.Core.Model.Ppmu;
using Testrong.Core.Model.Relay;
using Testrong.Core.Primitives;
using Testrong.Core.Primitives.Extend;
using Testrong.Core.Primitives.Service.AcTiming;
using Testrong.Core.Primitives.TestrongSystem;

namespace Testrong.User.Program
{
    /// <summary>
    /// ALL BOARDS
    /// </summary>
    public enum TestVersion
    {
        Board_1K_FT,
        Board_1K_CP,
        Board_2K_FT,
        Board_2K_CP,
        Board_Ppmu_CP,
        Board_Ppmu_FT,
        KM_2
    }
    /// <summary>
    /// Test Parameters 
    /// </summary>
    public class TestParaSet
    {
        public int delayMs;
        public int avgTimes;
        public double samDelay;
    }
    public class TestInfoSet
    {
        public string chType;
        public string Mode;
        public List<string> Range;
        public List<int> Channel;
    }

    public class Json
    {
        public int Version { get; set; }
        public bool Default { get; set; }
        public List<int> PMU_FVMV { get; set; }
        public List<int> PMU_FVMI { get; set; }
        public List<int> PMU_FIMV { get; set; }
        public List<int> PMU_FZMV { get; set; }
        public List<int> DPS_FVMV { get; set; }
        public List<int> DPS_FVMI { get; set; }
        public List<int> DPS_FIMV { get; set; }

    }

    public class UserProgram : TestrongCode
    {
        //-----global Parameters-----
        #region 路径定义
        const string EXT_CAL_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\ExtCal\\";
        const string EXT_CAL_MV_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\ExtCal_bak\\";
        const string EXT_CAL_HISTORY_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\ExtCal_History\\";
        const string EXT_CAL_INIT_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\Init_Files\\";
        const string EXT_CAL_FREQ_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\Ext_Freq\\";
        const string EXT_CAL_FREQ_MV_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\Ext_Freq_bak\\";
        const string EXT_CAL_FREQ_HISTORY_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\Ext_FreqHistory\\";
        const string EXT_CAL_INITVALUE_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\DPSPPMUParam\\";
        const string DOWN_INITVALUE_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\DownInitValue\\";
        const string EXT_CAL_BOARDINFO_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\DeliverInspection\\BoardInfo\\";
        const string CAL_COMPFILE_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\ExtInstrumentCalRecord\\CalResult\\";
        const string CAL_PRECHECK_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\ExtInstrumentCalRecord\\PreCheck\\";
        const string CAL_POSTCHECK_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\ExtInstrumentCalRecord\\PostCheck\\";
        const string RINT_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\RintCal\\";
        const string RINT_COMPFILE_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\RintCal\\CalResult\\";
        const string RINT_FILE_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\RintCal\\PMUR\\";
        const string RINT_PRECHECK_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\RintCal\\PreCheck\\";
        const string RINT_POSTCHECK_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\RintCal\\PostCheck\\";
        const string RINT_FAILLOG_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\RintCal\\FailResult\\";
        const string RETEST_LOG_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\ExtInstrumentCalRecord\\FailLog.csv";
        const string CONFIG_JSON_PATH = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\Init_Files\\config.json";
        const string METADATA_PATH = EXT_CAL_PATH + "metadata" + ".csv";
        #endregion


        #region FVMV
        Dictionary<string, TestParaSet> avgDelays_fvmv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 40, avgTimes = 255, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 15, avgTimes = 128, samDelay = 100 } },

        };
        Dictionary<string, TestParaSet> avgDelays_fvmv_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 40, avgTimes = 64, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"1A", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
        };
        #endregion
        #region FZMV
        Dictionary<string, TestParaSet> avgDelays_fzmv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 30, avgTimes = 200 ,samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 10, avgTimes = 200, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 10, avgTimes = 200, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 10, avgTimes = 200, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 10, avgTimes = 128, samDelay = 100 } },
        };
        #endregion
        #region FIMV PMU
        Dictionary<string, TestParaSet> avgDelays_1kft_fimv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 60, avgTimes = 128, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_1kcp_fimv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 200, avgTimes = 255, samDelay = 200 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2kft_fimv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 60, avgTimes = 255, samDelay = 300 } },
            {"20uA", new TestParaSet{delayMs = 60, avgTimes = 255, samDelay = 200 } },
            {"200uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 25, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 400 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmucp_fimv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 60, avgTimes = 255, samDelay = 300 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 128, samDelay = 300 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 300 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmuft_fimv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 60, avgTimes = 255, samDelay = 300 } },
            {"20uA", new TestParaSet{delayMs = 60, avgTimes = 255, samDelay = 200 } },
            {"200uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 25, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 400 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2km_fimv_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 60, avgTimes = 255, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 128, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
        };
        #endregion
        #region FIMV DPS
        Dictionary<string, TestParaSet> avgDelays_1kft_fimv_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 250, avgTimes = 64, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 70, avgTimes = 64, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_1kcp_fimv_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 250, avgTimes = 64, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 70, avgTimes = 64, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2kft_fimv_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 250, avgTimes = 16, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 100, avgTimes = 16, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 16, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 16, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 15, avgTimes = 16, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmucp_fimv_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 250, avgTimes = 64, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 70, avgTimes = 64, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmuft_fimv_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 250, avgTimes = 64, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 70, avgTimes = 64, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2km_fimv_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 250, avgTimes = 64, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 70, avgTimes = 64, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 20, avgTimes = 64, samDelay = 100 } },
        };
        #endregion
        #region FVMI PMU
        Dictionary<string, TestParaSet> avgDelays_1kft_fvmi_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 128, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 10, avgTimes = 64, samDelay = 100} },
            {"2mA", new TestParaSet{delayMs = 10, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_1kcp_fvmi_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 500 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 200 } },
            {"200uA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 200 } },
            {"2mA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 200 } },
            {"60mA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2kft_fvmi_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 300 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmucp_fvmi_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 500 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 300 } },
            {"200uA", new TestParaSet{delayMs = 10, avgTimes = 128, samDelay = 200 } },
            {"2mA", new TestParaSet{delayMs = 30, avgTimes = 128, samDelay = 200 } },
            {"60mA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmuft_fvmi_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 300 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2km_fvmi_pmu = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 500 } },
            {"20uA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 500 } },
            {"200uA", new TestParaSet{delayMs = 10, avgTimes = 128, samDelay = 500 } },
            {"2mA", new TestParaSet{delayMs = 10, avgTimes = 128, samDelay = 500 } },
            {"60mA", new TestParaSet{delayMs = 10, avgTimes = 255, samDelay = 500 } },
        };
        #endregion
        #region FVMI DPS
        Dictionary<string, TestParaSet> avgDelays_1kft_fvmi_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 30, avgTimes = 64, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 30, avgTimes = 64, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
            {"1A", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_1kcp_fvmi_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 64, samDelay = 100 } },
            {"1A", new TestParaSet{delayMs = 30, avgTimes = 64, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2kft_fvmi_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 500 } },
            {"20uA", new TestParaSet{delayMs = 30, avgTimes =255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"1A", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmucp_fvmi_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 100 } },
            {"20uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 300 } },
            {"200uA", new TestParaSet{delayMs = 50, avgTimes = 128, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 50, avgTimes = 128, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 200 } },
            {"1A", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 200 } },
        };
        Dictionary<string, TestParaSet> avgDelays_ppmuft_fvmi_dps = new Dictionary<string, TestParaSet>()
        {
             {"5uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 500 } },
            {"20uA", new TestParaSet{delayMs = 30, avgTimes =255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 15, avgTimes = 255, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 15, avgTimes = 255, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
            {"1A", new TestParaSet{delayMs = 20, avgTimes = 255, samDelay = 100 } },
        };
        Dictionary<string, TestParaSet> avgDelays_2km_fvmi_dps = new Dictionary<string, TestParaSet>()
        {
            {"5uA", new TestParaSet{delayMs = 70, avgTimes = 255, samDelay = 500 } },
            {"20uA", new TestParaSet{delayMs = 50, avgTimes = 255, samDelay = 100 } },
            {"200uA", new TestParaSet{delayMs = 50, avgTimes = 128, samDelay = 100 } },
            {"2mA", new TestParaSet{delayMs = 50, avgTimes = 128, samDelay = 100 } },
            {"60mA", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 100 } },
            {"1A", new TestParaSet{delayMs = 30, avgTimes = 255, samDelay = 500 } },
        };
        #endregion

        #region Variables Definition
     
        readonly List<string> testRangesPmu = new List<string> { "5uA", "20uA", "200uA", "2mA", "60mA" };
        readonly List<string> testRangesDps = new List<string> { "5uA", "20uA", "200uA", "2mA", "60mA", "1A" };
        readonly string[] FreqStr_Test = { "1M", "2M", "2.5M", "5M", "10M" };
        readonly double[] FreqForce_Test = { 1000000, 2000000, 2500000, 5000000, 10000000 };
        readonly Dictionary<string, string> FreqInfo = new Dictionary<string, string>()
        {
            {"0.625M", "NOR_Pattern_1" },
            {"1M", "NOR_Pattern_1" },
            {"2M", "NOR_Pattern_2"},
            {"2.5M", "NOR_Pattern_2"},
            {"5M", "NOR_Pattern_3"},
            {"10M","NOR_Pattern_4"},
            {"20M","NOR_Pattern_5"}
        };
        readonly List<int> testChannelDps_1K = new List<int>()
        {
            1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
            17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
        };
        readonly List<int> testChannelDps_2K = new List<int>()
        {
            1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
            17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,
            33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,
            49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64
        };
        public static class DpsPinConfig
        {
            public static readonly string[] allDpsPinNames_1K = {
            "DPS1","DPS2","DPS3","DPS4","DPS5","DPS6","DPS7","DPS8","DPS9","DPS10",
            "DPS11","DPS12","DPS13","DPS14","DPS15","DPS16","DPS17","DPS18","DPS19","DPS20",
            "DPS21","DPS22","DPS23","DPS24","DPS25","DPS26","DPS27","DPS28","DPS29","DPS30",
            "DPS31","DPS32"
             };
            public static readonly string[] allDpsPinNames_2K = {
            "DPS1","DPS2","DPS3","DPS4","DPS5","DPS6","DPS7","DPS8","DPS9","DPS10",
            "DPS11","DPS12","DPS13","DPS14","DPS15","DPS16","DPS17","DPS18","DPS19","DPS20",
            "DPS21","DPS22","DPS23","DPS24","DPS25","DPS26","DPS27","DPS28","DPS29","DPS30",
            "DPS31","DPS32","DPS33","DPS34","DPS35","DPS36","DPS37","DPS38","DPS39","DPS40",
            "DPS41","DPS42","DPS43","DPS44","DPS45","DPS46","DPS47","DPS48","DPS49","DPS50",
            "DPS51","DPS52","DPS53","DPS54","DPS55","DPS56","DPS57","DPS58","DPS59","DPS60",
            "DPS61","DPS62","DPS63","DPS64"
            };
            public static readonly Dictionary<TestVersion, string[]> Select_DpsPin = new Dictionary<TestVersion, string[]>()
            {
                { TestVersion.Board_1K_FT, allDpsPinNames_1K },
                { TestVersion.Board_1K_CP, allDpsPinNames_1K },
                { TestVersion.Board_2K_FT, allDpsPinNames_2K },
                { TestVersion.Board_2K_CP, allDpsPinNames_2K },
                { TestVersion.Board_Ppmu_CP, allDpsPinNames_1K },
                { TestVersion.Board_Ppmu_FT, allDpsPinNames_1K },
                { TestVersion.KM_2, allDpsPinNames_2K}
            };
        }
        
        readonly Dictionary<TestVersion, string> Select_IP = new Dictionary<TestVersion, string>()
        {
            { TestVersion.Board_1K_FT, "192.168.100.110" },
            { TestVersion.Board_1K_CP, "192.168.100.110" },
            { TestVersion.Board_2K_FT, "192.168.100.10" },
            { TestVersion.Board_2K_CP, "192.168.100.10" },
            { TestVersion.Board_Ppmu_CP, "192.168.100.10" },
            { TestVersion.Board_Ppmu_FT, "192.168.100.10" },
            { TestVersion.KM_2, "192.168.100.10"}
        };
        readonly Dictionary<TestVersion, int> Select_Temp = new Dictionary<TestVersion, int>()
        {
            { TestVersion.Board_1K_FT, 4 },
            { TestVersion.Board_1K_CP, 4 },
            { TestVersion.Board_Ppmu_CP, 4 },
            { TestVersion.Board_Ppmu_FT, 4 },
            { TestVersion.Board_2K_CP, 8 },
            { TestVersion.Board_2K_FT, 8 },
            { TestVersion.KM_2, 8}
        };
        public static Dictionary<int, TestVersion> Select_Version = new Dictionary<int, TestVersion>()
        {
            {1, TestVersion.Board_1K_FT},
            {2, TestVersion.Board_1K_CP},
            {3, TestVersion.Board_2K_FT},
            {4, TestVersion.Board_2K_CP},
            {5, TestVersion.Board_Ppmu_FT},
            {6, TestVersion.Board_Ppmu_CP},
            {7, TestVersion.KM_2 }
        };
        readonly Dictionary<string, PpmuMode> ModesPmu = new Dictionary<string, PpmuMode>()
        {
            {"FVMV",PpmuMode.FVMV},{"FVMI",PpmuMode.FVMI},{"FIMV",PpmuMode.FIMV}, {"FZMV",PpmuMode.FZMV}
        };
        readonly Dictionary<string, DpsMode> ModesDps = new Dictionary<string, DpsMode>()
        {
            {"FVMV",DpsMode.FVMV},{"FVMI",DpsMode.FVMI},{"FIMV",DpsMode.FIMV}
        };
        readonly Dictionary<string, PpmuIRange> RangesPmu = new Dictionary<string, PpmuIRange>()
        {
            {"5uA", PpmuIRange._5uA},
            {"20uA", PpmuIRange._20uA},
            {"200uA", PpmuIRange._200uA},
            {"2mA", PpmuIRange._2mA},
            {"60mA", PpmuIRange._60mA},
        };
        readonly Dictionary<string, DpsIRange> RangesDps = new Dictionary<string, DpsIRange>()
        {
            {"5uA", DpsIRange._5uA},
            {"20uA", DpsIRange._20uA},
            {"200uA", DpsIRange._200uA},
            {"2mA", DpsIRange._2mA},
            {"60mA", DpsIRange._60mA},
            {"1A", DpsIRange._1A}
        };
        readonly Dictionary<string, double> DmmCurrRanges = new Dictionary<string, double>()
        {
            {"5uA",0.000005},{"20uA",0.00002},{"200uA",0.0002},{"2mA",0.002},{"60mA",0.06},{"1A",1 }
        };
        readonly Dictionary<string, string> Rname = new Dictionary<string, string>()
        {
            {"R1","5uA"},{"R2","20uA"},{"R3","200uA"},{"R4","2mA"},{"R5","60mA"},{"R6","1A"}
        };
        readonly Dictionary<string, double> FiRanges = new Dictionary<string, double>()
        {
            {"5uA",0.000005},{"20uA",0.000015},{"200uA",0.0001},{"2mA",0.001},{"60mA",0.03}
        };
        readonly double[] rLimit = { 50, 120, 110, 1, 1, 1 };
        readonly double[] CurrScale = { -0.8, -0.5, 0, 0.5, 0.8 };
        readonly Dictionary<string, string> strRloadFvmi = new Dictionary<string, string>()
        {
            {"5uA", "1M"},
            {"20uA", "402K"},
            {"200uA", "49.9K"},
            {"2mA", "4.99K"},
            {"60mA", "150"},
            {"1A", "10"},
        };
        readonly Dictionary<string, ExtCaliLoad> Rcut_MIFI = new Dictionary<string, ExtCaliLoad>()
        {
            {"5uA", ExtCaliLoad.RC_RL13},
            {"20uA", ExtCaliLoad.RC_RL12},
            {"200uA", ExtCaliLoad.RC_RL10},
            {"2mA", ExtCaliLoad.RC_RL8},
            {"60mA", ExtCaliLoad.RC_RL5},
            {"1A", ExtCaliLoad.RC_RL3},
        };
        readonly int PmuChannelCount = 256;
        readonly double VoltageInitialDefault = -7.5;
        readonly double VoltageStepDefault = 3.75;
        readonly double VoltageInitialDps1A = 1.5;
        readonly double VoltageStepDps1A = 0.75;
        readonly double VoltageInitialSet = -5;
        readonly double VoltageStepSet = 2.5;
        readonly double[] VoltageStep20uA = { 2.5, 2.5, 3.75, 3.75, 3.75 };
        readonly int SampliCount = 5;
        readonly List<TestInfoSet> TestInfo = new List<TestInfoSet>();
        readonly int port = 200;
        readonly string ksightConnStr = "GPIB1::22::INSTR";
        readonly TestVersion SelectTestVersion = Select_Version[Readjson(CONFIG_JSON_PATH).Version];
        const int ChannelCount = 256;
        readonly double[] rInt = new double[ChannelCount];

        

        #endregion

        #region 函数定义

        /// <summary>
        /// Read JSON From json_path
        /// </summary>
        /// <param name="json_path">The Path of JSON</param>
        /// <returns>Json TYPE</returns>
        public static Json Readjson(string json_path)
        {
            Json get = new Json();
            using (StreamReader sr = new StreamReader(json_path))
            {
                string json = sr.ReadToEnd();
                get = JsonConvert.DeserializeObject<Json>(json);
            }
            return get;
        }

        /// <summary>
        /// Metadata_handler, Write metadata.csv
        /// Also Prevents thread conflict
        /// </summary>
        /// <param name="swdata">File Handler, Should be Initialized ahead,</param>
        /// <param name="SlotNum">Current Slot Number, </param>
        /// <param name="slotList">Slot List, </param>
        /// <param name="arm_dna">DNA Data from Zynq, </param>
        /// <param name="context">info from ATE Software, </param>
        /// <param name="init_Flag">choose from Header to Body| True=Header/False=Body, </param>
        /// <param name="Type">[OPTIONAL] Only need if init_Flag == False, Channel Type, Possible Value="PMU","DPS", "NULL"(Default), </param>
        /// <param name="Channel">[OPTIONAL] Only need if init_Flag == False, Channel Number, Default = -1, </param>
        /// <param name="Mode">[OPTIONAL] Only need if init_Flag == False, Test Mode, Possible Value="FVMV","FVMI","FIMV","FIMI","FZMV"(PMU Only), "NULL"(Default),</param>
        /// <param name="Rload">[OPTIONAL] Only need if init_Flag == False,Resistance Load, Default = "NaN", </param>
        /// <param name="Range">[OPTIONAL] Only need if init_Flag == False,Range, Possible Value="5uA", "20uA", "200uA", "2mA", "60mA", "1A"(DPS Only), Default  = "N/A", </param>
        /// <param name="filepath">[OPTIONAL] Only need if init_Flag == False, CSV File Path, Default = "N/A", </param>
        /// <param name="filetime">[OPTIONAL] Only need if init_Flag == False, CSV File Creation Time, Default = "N/A"</param>
        public void Metadata_handler(StreamWriter swdata, int SlotNum, List<int> slotList, string arm_dna, IFlowRunnerContext context, bool init_Flag, string Type = "NULL", int Channel = -1, string Mode = "NULL", string Rload = "NaN", string Range = "N/A", string filepath = "N/A", string filetime = "N/A")
        {
            //Are We Writing the header of MetaData?
            if (init_Flag == true)
            {
                //Each Slot has its own Thread
                //But We DON'T want to run in parallel in this case(Cali&Write file) 
                //So We Should Check Which Slot We Are Running...
                if (SlotNum == slotList[0])
                {
                    swdata.WriteLine("Tester_Name,Board_Id,Slot_Ip,Stil_Version");
                    for (int w = 0; w < 12; w++)//修改为12SLOT
                    {
                        if (w == (slotList[0] - 1))
                        {
                            swdata.WriteLine($"Slot{SlotNum},{arm_dna},{context.Communicator.ServerIP},V1.0.0");
                        }
                        else
                        {
                            swdata.WriteLine($"Slot{(w + 1)}");
                        }
                    }
                    for (int i = 0; i < 1; i++)
                    {
                        swdata.WriteLine();
                    }
                    swdata.Write("Slot_Dna,Channel_Type,Channel_No,Mode,R_Load,I_Range,V_Range,Meas_Range,File_Path,File_Time\n");
                }
                else
                {
                    int slotIndex = slotList.FindIndex(x => x.Equals(SlotNum));
                    StreamReader sr = new StreamReader(EXT_CAL_PATH + "metadata_temp" + ".csv", Encoding.UTF8);
                    int line = 0;
                    while (!sr.EndOfStream)
                    {
                        string tmp = sr.ReadLine();
                        if (line == slotList[slotIndex])
                        {
                            swdata.WriteLine("Slot" + SlotNum + "," + arm_dna + "," + context.Communicator.ServerIP + "," + "V1.0.0");
                        }
                        else
                        {
                            swdata.WriteLine(tmp);
                        }
                        line++;
                    }
                    sr.Close();
                    File.Delete(EXT_CAL_PATH + "metadata_temp" + ".csv");
                }
            }
            //Now We Are Writing the body of the file
            else
            {
                swdata.Write($"{arm_dna},");
                swdata.Write($"{Type},");
                if (Type == "PMU")
                {
                    swdata.Write($"{Channel},");
                }
                else
                {
                    swdata.Write($"PS{Channel},");
                }
                swdata.Write($"{Mode},");
                swdata.Write($"{Rload},");
                swdata.Write($"{Range},");
                swdata.Write("20V,");
                swdata.Write("13V,");
                swdata.Write($"{filepath},");
                swdata.Write($"{filetime}\n");
                swdata.Flush();
            }
        }

        /// <summary>
        /// Move Folder to Bak/History
        /// </summary>
        /// <param name="SlotNum">Current Slot Number, </param>
        /// <param name="slotList">Slot List, </param>
        /// <param name="pathFlag">Path Selector, Possible Value="Freq","CAL_Single"(No Pre/Post),"CAL_Normal",</param>
        /// <param name="isPreCheck">[OPTIONAL] Only need if pathFlag =="CAL_Normal",PreCheck Flag, Default = false</param>
        public void File_Mover(int SlotNum, List<int> slotList, string pathFlag, bool isPreCheck = false)
        {
            string DateCode = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");

            string WritePath;
            string BakPath;
            string HistoryPath;

            switch (pathFlag)
            {
                case "Freq":
                    WritePath = EXT_CAL_FREQ_PATH;
                    HistoryPath = EXT_CAL_FREQ_HISTORY_PATH;
                    BakPath = EXT_CAL_FREQ_MV_PATH;
                    break;
                default:
                    WritePath = EXT_CAL_PATH;
                    HistoryPath = EXT_CAL_HISTORY_PATH;
                    BakPath = EXT_CAL_MV_PATH;
                    break;
            }

            try
            {
                if (SlotNum == slotList[0])
                {

                    if (pathFlag == "CAL_Normal")
                    {
                        if (isPreCheck == true)
                        {
                            EmptyDir(CAL_COMPFILE_PATH);
                            ClearPrePostFile(CAL_PRECHECK_PATH);
                            ClearPrePostFile(CAL_POSTCHECK_PATH);
                        }
                        else if (isPreCheck == false)
                        {
                            Thread.Sleep(1);
                        }
                    }

                    if (Directory.Exists(BakPath))
                    {
                        if (!Directory.Exists(HistoryPath))
                        {
                            Directory.CreateDirectory(HistoryPath);
                        }
                        Directory.Move(BakPath, HistoryPath + DateCode);
                    }
                    if (Directory.Exists(WritePath))
                    {
                        Directory.Move(WritePath, BakPath);
                    }
                    Directory.CreateDirectory(WritePath);
                }
                else
                {
                    File.Move(METADATA_PATH, EXT_CAL_PATH + "metadata_temp" + ".csv");
                }
            }
            catch (Exception ex)
            {
                LogRawText(ex.StackTrace);
                throw ex;
            }


        }

        /// <summary>
        /// Prevent thread run at the same time
        /// </summary>
        /// <param name="SlotNum">Current Slot Number, </param>
        /// <param name="slotList">Slot List, </param>
        /// <param name="pathFlag">Path Selector, Possible Value="Freq","CAL_Init","CAL","RINT","CAL_COM",</param>
        /// <param name="lockFlag"></param>
        public void SlotThreadLocker(int SlotNum, List<int> slotList, string pathFlag,bool lockFlag = false)
        {
            string WritePath;
            switch (pathFlag)
            {
                case "Freq":
                    WritePath = EXT_CAL_FREQ_PATH;
                    break;
                case "CAL_Init":
                    WritePath = EXT_CAL_INIT_PATH;
                    break;
                case "RINT":
                    WritePath = RINT_COMPFILE_PATH;
                    break;
                case "CAL_COM":
                    WritePath = CAL_COMPFILE_PATH;
                    break;
                default:
                    WritePath = EXT_CAL_PATH;
                    break;
            }
            if(lockFlag==true)
            {
                if (SlotNum != slotList[0])                                                                 //If we are NOT the FIRST slot in the list
                {
                    int slotIndex = slotList.FindIndex(x => x.Equals(SlotNum));
                    while (lockFlag)                                                                        //Do we need lock or just set the Flag as we are done
                    {
                        Thread.Sleep(1000);
                        if (File.Exists(WritePath + slotList[slotIndex - 1] + ".flag"))                     //Wait until previous thread flags completion
                        {
                            File.Delete(WritePath + slotList[slotIndex - 1] + ".flag");
                            break;
                        }
                    }
                }
            }
            else
            {
                if (SlotNum != slotList[slotList.Count - 1])                                             //If we are NOT the LAST slot in the list
                {
                    StreamWriter swSignal = new StreamWriter(WritePath + SlotNum + ".flag");            //Create file flagging end of current thread
                    swSignal.WriteLine();
                    swSignal.Flush();
                    swSignal.Close();
                }
            }
        }
        private int GetPMUTempSensorIndex(int channel)
        {
            if ((channel >= 65 && channel <= 80) || (channel >= 97 && channel <= 112) || (channel >= 193 && channel <= 208) || (channel >= 241 && channel <= 256))
            {
                return 0;
            }
            else if ((channel >= 1 && channel <= 16) || (channel >= 49 && channel <= 64) || (channel >= 129 && channel <= 144) || (channel >= 161 && channel <= 176))
            {
                return 1;
            }
            else if ((channel >= 17 && channel <= 32) || (channel >= 33 && channel <= 48) || (channel >= 145 && channel <= 160) || (channel >= 177 && channel <= 192))
            {
                return 2;
            }
            else if ((channel >= 81 && channel <= 96) || (channel >= 113 && channel <= 128) || (channel >= 209 && channel <= 224) || (channel >= 225 && channel <= 240))
            {
                return 3;
            }
            else return -1;
        }

        private int GetDPSTempSensorIndex(int channel)
        {
            return ((channel - 1) / 4);
        }

        public int GetFileSize(string path)
        {
            System.IO.FileInfo fileInfo = null;
            try
            {
                fileInfo = new System.IO.FileInfo(path);
            }
            catch
            {
                return 0;
            }
            if (fileInfo != null && fileInfo.Exists)
            {
                return (int)System.Math.Ceiling(fileInfo.Length / 1024.0);
            }
            else
            {
                return 0;
            }
        }

        public void ClearPrePostFile(string DirPath)
        {
            System.IO.DirectoryInfo di = new DirectoryInfo(DirPath);
            foreach (FileInfo file in di.GetFiles())
            {
                if (file.Name.EndsWith(".csv") && file.Name.IndexOf("FlowLog") == -1)
                {
                    file.Delete();
                }
            }
        }
        /// <summary>
        /// Delete Anything inside Folder
        /// </summary>
        /// <param name="DirPath"></param>
        public void EmptyDir(string DirPath)
        {
            System.IO.DirectoryInfo di = new DirectoryInfo(DirPath);
            foreach (FileInfo file in di.EnumerateFiles())
            {
                file.Delete();
            }
            ;
        }
        private string[] GetAllPmuPins()
        {
            string[] ans = new string[256];
            for (int i = 0; i < ans.Length; i++)
            {
                ans[i] = "A" + (i < 9 ? "0" : "") + (i + 1);
            }
            return ans;
        }

        /// <summary>
        /// Get ATE Measure Result
        /// </summary>
        /// <param name="InfoList">SiteInfo</param>
        /// <param name="PinName">PinName</param>
        /// <returns>double Measured Value</returns>
        private double GetATEChannelMeasure(List<SiteInfo> InfoList, string[] PinName)
        {
            double result = 0;
            foreach (SiteInfo si in InfoList)
            {
                bool flag = false;
                foreach (ChannelInfo ci in si.Channels)
                {
                    if (ci.Name == PinName[0])
                    {
                        flag = true;
                        result = ci.Result;
                        break;
                    }
                }
                if (flag) break;
            }
            return result;
        }

        /// <summary>
        /// Get Rload
        /// Will Loop Measure 100 times,do average
        /// And measure 101th
        /// Then Compare the difference between them
        /// if Out-Of-Limit
        /// Will Try Again
        /// For INIFINATE Times
        /// </summary>
        /// <param name="rdmm">DMM Handler</param>
        /// <param name="range">DMM Measure Range</param>
        /// <param name="limit">Resistance Diff limit</param>
        /// <returns></returns>
        private double GetRloadValue(KeysightDMM3458A rdmm, double range, double limit)
        {
            double value = 0;
            while (true)
            {
                double sum = 0;
                for (int i = 0; i < 100; i++)
                {
                    double r1 = rdmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.RES, 1, range);
                    sum = sum + r1;
                }
                sum = sum / 100;
                double r2 = rdmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.RES, 1, range);
                if (Math.Abs(sum - r2) < limit)
                {
                    value = r2;
                    break;
                }
            }
            return value;

        }
        private void SortAsFileCreationTime(ref FileInfo[] arrFi)
        {
            Array.Sort(arrFi, delegate (FileInfo x, FileInfo y)
            {
                return x.CreationTime.CompareTo(y.CreationTime);
            }
            );
        }
        public List<Dictionary<string, string>> ReadRload(string ResFilePath)
        {
            Dictionary<string, string> RlPmuFv = new Dictionary<string, string>();
            Dictionary<string, string> RlPmuFi = new Dictionary<string, string>();
            Dictionary<string, string> RlDpsFv = new Dictionary<string, string>();
            Dictionary<string, string> RlDpsFi = new Dictionary<string, string>();
            List<Dictionary<string, string>> RloadTuple = new List<Dictionary<string, string>>();
            int cnt1 = 0;
            StreamReader ResReader = new StreamReader(ResFilePath, Encoding.UTF8);
            while (!ResReader.EndOfStream)
            {
                string rtemp = ResReader.ReadLine();
                string rname = rtemp.Split(',')[0];
                string rvalue = rtemp.Split(',')[1];
                rname = rname.Split('_')[1];
                if (cnt1 < 5)
                {
                    RlPmuFv.Add(Rname[rname], rvalue);
                    RlPmuFi.Add(Rname[rname], rvalue);
                }
                else if (cnt1 < 11)
                {
                    RlDpsFv.Add(Rname[rname], rvalue);
                    if (cnt1 < 10)
                    {
                        RlDpsFi.Add(Rname[rname], rvalue);
                    }
                }
                cnt1 = cnt1 + 1;
            }
            RloadTuple.Add(RlPmuFv);
            RloadTuple.Add(RlPmuFi);
            RloadTuple.Add(RlDpsFv);
            RloadTuple.Add(RlDpsFi);
            ResReader.Close();
            return RloadTuple;
        }
        public double[,] ReadRext(string RextFilePath)
        {
            // 检查文件是否存在
            //if (!File.Exists(RextFilePath))
            //{
            //    return new double[0, 0];
            //}
            if (!File.Exists(RextFilePath))
            {
                LogRawText($"错误：找不到外部电阻文件 {RextFilePath}，请检查文件是否存在。");
                throw new FileNotFoundException($"外部电阻文件不存在: {RextFilePath}");
            }


            try
            {
                // 先读取文件以确定行数和列数
                string[] lines = File.ReadAllLines(RextFilePath);
                if (lines.Length == 0)
                {
                    return new double[0, 0];
                }

                // 确定列数（通过第一行）
                int columns = lines[0].Split(',').Length;

                // 创建适当大小的数组
                double[,] ExtBoard_Res = new double[lines.Length, columns];

                // 填充数据
                for (int i = 0; i < lines.Length; i++)
                {
                    string[] values = lines[i].Split(',');
                    for (int j = 0; j < Math.Min(values.Length, columns); j++)
                    {
                        if (double.TryParse(values[j], out double result))
                        {
                            ExtBoard_Res[i, j] = result;
                        }
                        else
                        {
                            ExtBoard_Res[i, j] = 0;
                        }
                    }
                }

                return ExtBoard_Res;
            }
            catch
            {
                // 如果发生任何异常，返回空数组
                return new double[0, 0];
            }
        }
        public double[] ReadRint(string RintFilePath)
        {
            double[] IntBoard_Res = new double[256];
            int cnt3 = 0;
            try
            {
                // 提前检查文件是否存在，避免深层构造器异常
                if (!File.Exists(RintFilePath))
                {
                    throw new FileNotFoundException($"File not found: {RintFilePath}");
                }

                using (var IntResReader = new StreamReader(RintFilePath, Encoding.UTF8))
                {
                    while (!IntResReader.EndOfStream)
                    {
                        string[] A = IntResReader.ReadLine().Split(' ', ':');
                        IntBoard_Res[cnt3] = Convert.ToDouble(A[4]);
                        cnt3 = cnt3 + 1;
                    }
                    IntResReader.Close();
                    return IntBoard_Res;
                }
            }
            catch (Exception ex)
            {
                LogRawText(ex.StackTrace); // 调用日志记录方法
                throw; // 重新抛出保留原始堆栈追踪
            }
        }
        public List<string> RangeTrans(List<int> range)
        {
            Dictionary<int, string> RangeMap = new Dictionary<int, string>
            {
                {1,"5uA"},
                {2,"20uA" },
                {3,"200uA" },
                {4,"2mA" },
                {5,"60mA" },
                {6,"1A" }
            };
            List<string> list = new List<string>();
            for (int i = 0; i < range.Count; i++)
            {
                list.Add(RangeMap[range[i]]);
            }
            return list;
        }
        public Dictionary<int, double[]> ReadBackDmm(double[] data, List<int> listCh)
        {
            Dictionary<int, double[]> DmmDic = new Dictionary<int, double[]>();
            int dmmFlag = 0;
            while (dmmFlag < data.Length)
            {
                int number = dmmFlag / SampliCount;
                int group = listCh[number];
                double[] DmmMeasure = new double[SampliCount];
                for (int readNum = dmmFlag; readNum < (number + 1) * SampliCount; readNum++)
                {
                    DmmMeasure[dmmFlag % SampliCount] = data[readNum];
                    dmmFlag += 1;
                }
                DmmDic.Add(group, DmmMeasure);
            }
            return DmmDic;
        }

        /// <summary>
        /// Write Data To File, Need import StreamWriter and close FileHandler after using this func
        /// !!! If you want to Do CUSTOM format, add new case for contextFormat
        /// </summary>
        /// <param name="sw">StreamWriter, Need to be initialized first</param>
        /// <param name="slot">Slot Number</param>
        /// <param name="dna">DNA Number</param>
        /// <param name="type">DPS/PMU</param>
        /// <param name="channel">Channel Number(PMU:1-256, DPS:1-32/64)</param>
        /// <param name="mode">FVMV/FVMI/FIMV/FZMV(PMU Only)</param>
        /// <param name="rload">External Resistance Load</param>
        /// <param name="extR">Internal Resistance On the External Calibration Board</param>
        /// <param name="range">Board Measurment Range(5uA; 20uA; 200uA; 2mA; 60mA; 1A(DPS Only))</param>
        /// <param name="ForceValue">ForceValue</param>
        /// <param name="AteMeasure">ATE Measure Value</param>
        /// <param name="DmmMeasure">DMM Measure Value</param>
        /// <param name="TempValue">Temperature Value(May Not Available)</param>
        /// <param name="contextFormat">[OPTIONAL] For custom CSV content</param>
        /// <param name="customData">[OPTIONAL]</param>
        /// <param name="SampliCount">[OPTIONAL]</param>
        public void WriteSingleFile(StreamWriter sw, int slot, string dna, string type, int channel, string mode, string rload, double[,] extR, string range, double[] ForceValue, double[] AteMeasure, double[] DmmMeasure, double[] TempValue, string contextFormat = "Normal", double[] customData = null, int SampliCount = 5)
        {
            switch (contextFormat)
            {
                case "Freq":                                                         
                    sw.Write("Channel_No,Freq_Force,Freq_Measure\n");
                    for(int ch=0; ch<channel;ch ++)
                    {
                        sw.Write($"{ch + 1},");
                        sw.Write($"{customData[2 * ch]:F3},");
                        sw.Write($"{customData[2 * ch + 1]:F5}\n");
                        sw.Flush();
                    }
                    break;
                case "RintGND":
                    sw.Write("Tester_Name,Foo\n");
                    sw.Write($"Slot_No,{slot}\n");
                    sw.Write($"Board_Dna,{dna}\n");
                    sw.Write("Channel_Type,PMU\n");
                    sw.Write($"Channel_No,{channel}\n");
                    sw.Write($"Mode,FVMI\n");
                    sw.Write($"R_Load,Hi-Z\n");
                    sw.Write($"R_Int,{0}\n");
                    sw.Write($"R_Ext,{0}\n");
                    sw.Write($"I_Range,2mA\n");
                    sw.Write("V_Range,20V\n");
                    sw.Write("Meas_Range,13V\n");
                    sw.Write("\n");
                    sw.Write($"Force_0V_MV={customData[0] * 1000:F8}mV\n");          //Write MV at ForceV=0
                    sw.Write($"Force_0V_MI={customData[1] * 1000:F8}mA\n");          //Write MI at ForceV=0
                    sw.Write("Force Voltage(mV),Measure Voltage(mV),Measure Current(mA),Diff_Voltage(mV),Resistance(FV/MI),Resistance(Caled),Temperature\n");
                    for (int writeLine = SampliCount; writeLine < SampliCount; writeLine++)
                    {
                        sw.Write($"{ForceValue[writeLine] * 1000:F8},");
                        sw.Write($"{customData[writeLine + 2] * 1000:F8},");         //customData[writeLine + 2] = Measure Voltage
                        sw.Write($"{AteMeasure[writeLine] * 1000:F8},");
                        sw.Write($"{(customData[writeLine + 2] - ForceValue[writeLine]) * 1000:F8},");
                        sw.Write($"{ForceValue[writeLine] / AteMeasure[writeLine]:F8},");
                        sw.Write($"{(ForceValue[writeLine]- customData[0]) / (AteMeasure[writeLine]- customData[1]):F8},");
                        sw.Write($"{TempValue[writeLine]:F8}\n");
                    }
                    break;
                case "Normal":
                default:
                    sw.Write("Tester_Name,Foo\n");
                    sw.Write($"Slot_No,{slot}\n");
                    sw.Write($"Board_Dna,{dna}\n");
                    sw.Write($"Channel_Type,{type}\n");
                    sw.Write($"Channel_No,{channel}\n");
                    sw.Write($"Mode,{mode}\n");
                    sw.Write($"R_Load,{rload}\n");
                    sw.Write($"R_Int,{0}\n");
                    if (type == "PMU")
                    {
                        sw.Write($"R_Ext,{extR[channel - 1, slot - 1]}\n");
                    }
                    else
                    {
                        sw.Write($"R_Ext,{0}\n");
                    }
                    sw.Write($"I_Range,{range}\n");
                    sw.Write("V_Range,20V\n");
                    sw.Write("Meas_Range,13V\n");
                    sw.Write("\n");
                    sw.Write("Force Value,ATE Measure,DMM Measure,Temperature\n");
                    for (int writeLine = 0; writeLine < SampliCount; writeLine++)
                    {

                        if (mode == "FVMV" || mode == "FZMV")
                        {
                            sw.Write($"{ForceValue[writeLine]:F8},");
                            sw.Write($"{AteMeasure[writeLine]:F8},");
                            sw.Write($"{DmmMeasure[writeLine]:F8},");
                        }
                        else if (mode == "FVMI")
                        {
                            if (range == "60mA" || range == "1A")
                            {
                                sw.Write($"{ForceValue[writeLine]:F10},");
                                sw.Write($"{AteMeasure[writeLine]:F15},");
                                sw.Write($"{DmmMeasure[writeLine]:F15},");                              //DMM at Current Mode
                            }
                            else
                            {
                                sw.Write($"{ForceValue[writeLine]:F10},");
                                sw.Write($"{AteMeasure[writeLine]:F15},");
                                sw.Write($"{(DmmMeasure[writeLine] / Convert.ToDouble(rload)):F15},");
                            }
                        }
                        else if (mode == "FIMV")
                        {
                            if (range == "60mA" || range == "5uA")
                            {
                                sw.Write($"{ForceValue[writeLine]:F10},");
                                sw.Write($"{AteMeasure[writeLine]:F15},");
                                sw.Write($"{(DmmMeasure[writeLine] / Convert.ToDouble(rload)):F15},");
                            }
                            else
                            {
                                sw.Write($"{ForceValue[writeLine]:F10},");
                                sw.Write($"{AteMeasure[writeLine]:F15},");
                                sw.Write($"{(DmmMeasure[writeLine] / Convert.ToDouble(rload)):F15},");
                            }
                        }
                        sw.Write($"{TempValue[writeLine]:F8}\n");
                    }
                    break;
            }
        }

        #endregion

        #region TestCase
        private void FrequencyProcess(int slot, StreamWriter sw, string filepath, int failcount)
        {
            DirectoryInfo di = new DirectoryInfo(filepath);
            FileInfo[] arrFi = di.GetFiles("*.csv");
            SortAsFileCreationTime(ref arrFi);
            List<string> fileset = new List<string>();
            for (int x = 0; x < arrFi.Length; x++)
            {
                if (arrFi[x].Name.Contains("Slot" + slot) == true)
                {
                    fileset.Add(arrFi[x].Name);
                }
            }
            //get acc_min and acc_max
            double acc_min = 0;
            double acc_max = 0;
            for (int i = 0; i < fileset.Count; i++)
            {
                int count = 0;
                int line = 0;
                List<double> data = new List<double>();
                List<double> data_empty = new List<double>();
                StreamReader sr = new StreamReader(filepath + fileset[i], Encoding.UTF8);
                while (!sr.EndOfStream)
                {
                    string rtemp = sr.ReadLine();
                    if (line > 0)
                    {
                        double rvalue = Convert.ToDouble(rtemp.Split(',')[2]);
                        if (rvalue != -1)
                        {
                            data.Add(rvalue);
                            count = count + 1;
                        }
                        else
                        {
                            data_empty.Add(rvalue);
                        }
                    }
                    line = line + 1;
                }
                sr.Close();
                string item = fileset[i];
                string Drived = item.Split('_')[2];
                Drived = Drived.Substring(0, Drived.Length - 5);
                if (data_empty.Count == 256)
                {
                    sw.WriteLine($"{item.Substring(0, item.Length - 4)},{item[4]},{Drived},IO,{0},FALSE,");
                }
                else
                {
                    double max = data.Max();
                    double min = data.Min();
                    double value = Convert.ToDouble(Drived) * 1000000;
                    acc_min = min / value;
                    acc_max = max / value;
                    string acc_flag = "FALSE";
                    double diff = Math.Abs(Math.Max(acc_min, acc_max) - 1);
                    if ((diff < 0.005) && (count > failcount))
                    {
                        acc_flag = "TRUE";
                    }
                    sw.WriteLine($"{item.Substring(0, item.Length - 4)},{item[4]},{Drived},IO,{acc_max},{acc_flag},");
                }
                data.Clear();
                data_empty.Clear();
                sw.Flush();
            }
        }

        void ExternalCalibrationFreqCollect(IFlowRunnerContext context, TestVersion testVersion)
        {
            //config DMM53220A
            Keysight53220A FreqCounter53220A = new Keysight53220A();
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string addressFreq = "USB0::0x0957::0x1807::MY63100296::INSTR";
            //config ExtCalibration Board
            string ExtConnStr = Select_IP[testVersion];
            int ExtPort = 200;
            string DateCode = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
            //config Board
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            byte[] armDnaPortCmd = new byte[2] { 14, 57 }; // command to read arm dna
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd); //send command
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString(); //convert hex dna to decimal
            int SlotNum = context.Communicator.SlotNo;

            //set channel number
            int[] ChannelPmu = new int[256];
            for (int n = 0; n < 256; n++)
            {
                ChannelPmu[n] = n + 1;
            }
            int PmuChannelCount = 256;
            string[] FreqStr = FreqStr_Test;
            double[] FreqForce = FreqForce_Test;
            double[] Period = new double[50];
            for (int i = 0; i < FreqStr.Length; i++)
            {
                string actimeing = $"{(1000000000 / FreqForce[i]):F2}";
                Period[i] = Convert.ToDouble(actimeing);
            }

            //creat dir
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "Freq");

            StreamWriter swResult;
            if (SlotNum == slotList[0])
            {
                swResult = new StreamWriter(EXT_CAL_FREQ_PATH + "f_Result.csv", true, Encoding.UTF8);
                swResult.WriteLine("Test_Item,Slot_No,Drived_Frequency(MHz),Channel_Type,Accuracy_Measure,Validation_Result");
                FreqCounter53220A.InitDMM53220A(addressFreq, Keysight53220A.KeysightMeasMode.FREQ);
                FreqCounter53220A.InitMeasure();
                Thread.Sleep(100);
                FreqCounter53220A.GetDmm53220AMeasureData();
                swResult.Close();
            }
            else
            {
                int slotIndex = slotList.FindIndex(x => x.Equals(SlotNum));
                while (true)
                {
                    Thread.Sleep(1000);
                    if (File.Exists(EXT_CAL_FREQ_PATH + slotList[slotIndex - 1] + ".flag")) //Wait until previous thread flags completion
                    {
                        File.Delete(EXT_CAL_FREQ_PATH + slotList[slotIndex - 1] + ".flag");
                        break;
                    }
                }
                FreqCounter53220A.InitDMM53220A(addressFreq, Keysight53220A.KeysightMeasMode.FREQ);
            }
            Thread.Sleep(100); 
            for (int fCount = 0; fCount < FreqStr.Length; fCount++) // 625K - 32M
            {
                double[] customData = new double[2 * PmuChannelCount];
                string FreqFileNmae = EXT_CAL_FREQ_PATH + "Slot" + SlotNum + "_" + "Freq" + "_" + FreqStr[fCount] + ".csv";
                StreamWriter sw = new StreamWriter(FreqFileNmae, true, Encoding.UTF8);
                Thread.Sleep(10);
                string strPattern = FreqInfo[FreqStr[fCount]];
                PATTERN.DCLevel.Set("level_5V");
                ACTimingSetting aCTimingInfo = new ACTimingSetting
                {
                    Period = Period[fCount],
                    PinName = GetAllPmuPins(),
                    FmtMode = FmtMode.RL,
                    EdgeInfo = new EdgeInfo()
                    {
                        DriverOn = 0,
                        DriverData = 0.3,
                        DriverReturn = 0.8,
                        Open = 0,
                        Close = 0,
                        CompareMode = CompareMode.Edge,
                    }
                };
                aCTimingInfo.Name = "TEST";
                PATTERN.ACTiming.Execute(aCTimingInfo); ;
                int read_count = 3;
                for (int loopk = 0; loopk < PmuChannelCount; loopk++)
                {
                    int ch = ChannelPmu[loopk];

                    extCaliHandle.SetPpmuExternalCalibration(ExtConnStr, ExtPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, ExtCaliLoad.no_load, 1); //@@rita,20240307
                    Thread.Sleep(500);
                    string[] PmuPinName = { ("A" + (loopk < 9 ? "0" : "") + (loopk + 1)) };
                    RELAY.SwitchToDigitalCard(PmuPinName);
                    Thread.Sleep(1);
                    PATTERN.Burst(strPattern, PmuPinName, 10, false, true);
                    Thread.Sleep(15);
                    double[] readValues = new double[read_count];//read 3 times
                    for (int j = 0; j < read_count; j++)
                    {
                        FreqCounter53220A.InitMeasure();
                        Thread.Sleep(50);
                        readValues[j] = FreqCounter53220A.GetDmm53220AMeasureData();
                    }
                    double freqValue = -1;
                    for (int j = 0; j < read_count; j++)
                    {
                        if (Math.Abs(FreqForce[fCount] - readValues[j]) < 10000)
                        {
                            freqValue = readValues[j];
                            break;
                        }
                    }
                    customData[2 * loopk] = FreqForce[fCount];
                    customData[2 * loopk + 1] = freqValue;
                    sw.Flush();
                }
                double[,] ZeroExtR = {
                                { 0.0 , 0.0 , 0.0}
                            };
                double[] Zero=new double[1];
                Zero[0] = 0;
                WriteSingleFile(
                    sw:sw,
                    slot:SlotNum,
                    dna:arm_dna,
                    type:"K7",
                    channel: PmuChannelCount,
                    mode:"Freq",
                    rload:"0",
                    extR: ZeroExtR,
                    range:"NULL",
                    ForceValue: Zero,
                    AteMeasure: Zero,
                    DmmMeasure: Zero,
                    TempValue: Zero,
                    contextFormat:"Freq",
                    customData:customData,
                    SampliCount: FreqStr.Length
                    );
                sw.Close();

            }
            FreqCounter53220A.CloseDMM53220A();
            swResult = new StreamWriter(EXT_CAL_FREQ_PATH + "f_Result.csv", true, Encoding.UTF8);
            FrequencyProcess(SlotNum, swResult, EXT_CAL_FREQ_PATH, 25);
            swResult.Close();
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "Freq");
            if (SlotNum == slotList[slotList.Count - 1])
            {
                swResult.Close();
            }
        }

        /// <summary>
        /// Reset Rint
        /// Empty Local Rint Folder and Files
        /// Put Initial Files into Zynq (Not only Rint,but also others)
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        void Rint_Reset(IFlowRunnerContext context)
        {
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            byte[] armDnaPortCmd = new byte[2] { 14, 57 }; // command to read arm dna
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd); //send command
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString(); //convert hex dna to decimal
            int SlotNum = context.Communicator.SlotNo;
            if (SlotNum == slotList[0])
            {
                if (Directory.Exists(RINT_PATH))
                {
                    EmptyDir(RINT_COMPFILE_PATH);
                    EmptyDir(RINT_FILE_PATH);
                    EmptyDir(RINT_PRECHECK_PATH);
                    EmptyDir(RINT_POSTCHECK_PATH);
                    EmptyDir(RINT_FAILLOG_PATH);
                }
                if (Directory.Exists(DOWN_INITVALUE_PATH))
                {
                    EmptyDir(DOWN_INITVALUE_PATH);
                }
                DelayHelper.Sleep(1);
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init", lockFlag: true);
            }
            else
            {
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init", lockFlag: true);
            }

            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            int FileKb = 0;
            string initValueFile = EXT_CAL_INITVALUE_PATH + context.Communicator.ServerIP + "_" + context.Communicator.ServerPort + "_InitValue.csv";
            string BoardInfoFile = EXT_CAL_BOARDINFO_PATH + context.Communicator.ServerIP + "_boardinfo.txt";
            ReadTftp DownFile = new ReadTftp();
            DownFile.DownloadFile(context.Communicator.ServerIP, DOWN_INITVALUE_PATH + context.Communicator.ServerIP + "_" + context.Communicator.ServerPort + "_InitValue.csv", ReadType.InitValue);
            FileKb = GetFileSize(DOWN_INITVALUE_PATH + context.Communicator.ServerIP + "_" + context.Communicator.ServerPort + "_InitValue.csv");
            if (FileKb > 10)
            {
                Thread.Sleep(1);
            }
            else
            {
                if (File.Exists(EXT_CAL_INITVALUE_PATH + context.Communicator.ServerIP + "_" + context.Communicator.ServerPort + "_InitValue.csv"))
                {
                    var isInitValueOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, initValueFile, FileType.InitValue);
                    LogRawText($"InitValue Status: {isInitValueOK}");
                }
            }
            if (File.Exists(BoardInfoFile))
            {
                var isBoardInfoOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, BoardInfoFile, FileType.boardinfo);
                LogRawText($"BoardInfo Status: {isBoardInfoOK}");
            }
            var isDnaUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, EXT_CAL_INIT_PATH + "Dna_init.csv", FileType.dna);
            LogRawText($"Dna Status: {isDnaUploadOK}");

            Thread.Sleep(10);
            var isMVUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, EXT_CAL_INIT_PATH + "MV_init.csv", FileType.mv);
            LogRawText($"MV Status: {isMVUploadOK}");

            Thread.Sleep(10);
            var isMIUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, EXT_CAL_INIT_PATH + "MI_init.csv", FileType.mi);
            LogRawText($"MI Status: {isMIUploadOK}");

            Thread.Sleep(10);
            var isPmurUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, EXT_CAL_INIT_PATH + "Pmur_init.csv", FileType.pmu_r);
            LogRawText($"Pmu_r Status: {isPmurUploadOK}");

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init");
        }

        /// <summary>
        /// To Pre-Test Rint with External Calibration Board
        /// Mainly get FVMV data to Calibrate ForceV
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        /// <param name="testVersion"></param>
        void Rint_FVMV_2mA_Pre(IFlowRunnerContext context, TestVersion testVersion)
        {
            #region Init Config & Variables
            List<int> ChannelDps = new List<int>();
            List<int> ChannelPmu = new List<int>();
            for (int m = 0; m < PmuChannelCount; m++)
            {
                ChannelPmu.Add(m + 1);
            }
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }

            //-----config Board-----
            byte[] armDnaPortCmd = new byte[2] { 14, 57 };
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd);
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;
            double[,] ExtBoard_Res = ReadRext(EXT_CAL_INIT_PATH + "ExtBoardRes.csv");

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: true);

            //Folder Related
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Single");


            //-----Start Slot Number-----
            StreamWriter swdata;
            swdata = new StreamWriter(METADATA_PATH, true, Encoding.UTF8)
            {
                AutoFlush = true
            }; 

                Metadata_handler(
                swdata: swdata,
                SlotNum: SlotNum,
                slotList: slotList,
                arm_dna: arm_dna,
                context: context,
                init_Flag: true
                );
            #endregion

            #region Config DMM
            //-----config dmm3458A and ExtCalibrationBoard----- 
            KeysightDMM3458A dmm = new KeysightDMM3458A();
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string extConnStr = Select_IP[testVersion];
            int extPort = port;

            dmm.InitDMM(ksightConnStr);
            #endregion


            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");

            #region The Test 
            for (int loopk = 0; loopk <PmuChannelCount; loopk++)
            {
                #region Test Config
                string[] PmuPinName = { ("A" + (ChannelPmu[loopk] < 10 ? "0" : "") + ChannelPmu[loopk]) };
                RELAY.SwitchMode(RelayMode.Open);
                RELAY.SwitchToPPMU(PmuPinName);
                double ForceVoltage = VoltageInitialDefault;
                double VoltageStep = VoltageStepDefault;
                string filepath = "Slot" + SlotNum + "_PMU_" + "ch" + ChannelPmu[loopk] + "_" + "FVMV" + "_" + "Hi-Z" + "_" + "2mA" + ".csv";
                string filename = EXT_CAL_PATH + filepath;
                int ch = ChannelPmu[loopk];

                double[] AteMeasure = new double[SampliCount];
                double[] ForceValue = new double[SampliCount];
                double[] DMMValue = new double[SampliCount];
                double[] TempValue = new double[SampliCount];
                #endregion

                extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, ExtCaliLoad.no_load, 0);//change channel

                if (loopk == 0)
                {
                    DelayHelper.Sleep(20);
                }
                #region Actual Test
                for (int p = 0; p < SampliCount; p++)
                {
                    PPMU.Force(PmuPinName, ForceVoltage, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);

                    Thread.Sleep(20);
                    List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), 128, 100);
                    double chResult = GetATEChannelMeasure(siList, PmuPinName);

                    double dmmRead = dmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.VOLT, 1, 7.5);//dmm 3458A read

                    double[] readTemp = PPMU.ReadTemperature();
                    double chTemp = readTemp[GetPMUTempSensorIndex(ch)];


                    ForceValue[p] = ForceVoltage;
                    AteMeasure[p] = chResult;
                    DMMValue[p] = dmmRead;
                    TempValue[p] = chTemp;
                    ForceVoltage += VoltageStep;
                }
                #endregion

                PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);
                #region File Writing
                StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                {
                    AutoFlush = true
                };
                WriteSingleFile(sw: sw,
                                slot: SlotNum,
                                dna: arm_dna,
                                type: "PMU",
                                channel: ch,
                                mode: "FVMV",
                                rload: "Hi-Z",
                                extR: ExtBoard_Res,
                                range: "2mA",
                                ForceValue: ForceValue,
                                AteMeasure: AteMeasure,
                                DmmMeasure: DMMValue,
                                TempValue: TempValue);

                sw.Flush();
                sw.Close();

                Metadata_handler(swdata: swdata,
                                 SlotNum: SlotNum,
                                 slotList: slotList,
                                 arm_dna: arm_dna,
                                 context: context,
                                 init_Flag: false,
                                 Type: "PMU",
                                 Channel: ch,
                                 Mode: "FVMV",
                                 Rload: "Hi-Z",
                                 Range: "2mA",
                                 filepath: filepath,
                                 filetime: filetime);
            
            #endregion
            }
            #endregion
            SlotThreadLocker(SlotNum: SlotNum,slotList: slotList, pathFlag: "CAL");
            swdata.Flush();
            swdata.Close();

        }

        /// <summary>
        /// Post-Test Rint with External Calibration Board
        /// Do FVMV Second time with MV Compensate
        /// Calculate Rint value and generate Pmu_r file
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        /// <param name="testVersion"></param>
        void Rint_FVMV_2mA_Post(IFlowRunnerContext context, TestVersion testVersion)
        {
            #region Init Config & Variables
            List<int> ChannelDps = new List<int>();
            List<int> ChannelPmu = new List<int>();
            //-----Select PreTest or ReTest-----
            for (int m = 0; m < PmuChannelCount; m++)
            {
                ChannelPmu.Add(m + 1);
            }
            //-----get all connect slot number-----
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            //-----config Board-----
            byte[] armDnaPortCmd = new byte[2] { 14, 57 };
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd);
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;

            //---------Thread Locker--------
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: true);

            //-----Move File To History-----
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Single");

            //-----Start Write MetaData-----
            StreamWriter swdata;
            swdata = new StreamWriter(METADATA_PATH, true, Encoding.UTF8)
            {
                AutoFlush = true
            };

                Metadata_handler(
                swdata: swdata,
                SlotNum: SlotNum,
                slotList: slotList,
                arm_dna: arm_dna,
                context: context,
                init_Flag: true
                );
            #endregion

            #region Config DMM
            //-----config dmm3458A and ExtCalibrationBoard----- 
            KeysightDMM3458A dmm = new KeysightDMM3458A();
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string extConnStr = Select_IP[testVersion];
            int extPort = port;

            dmm.InitDMM(ksightConnStr);
            #endregion

            //-----Read R File-----                
            double[,] ExtBoard_Res = ReadRext(EXT_CAL_INIT_PATH + "ExtBoardRes.csv");
            
            extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, 1, ExternalCalibrationMode.Channel, 1, ExtCaliVI.V, ExtCaliLoad.RC_RL7, 0);   //1kΩ
            double rload = GetRloadValue(dmm, 2000, 5);
            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
            
            
            #region The Test 
            
            for (int loopk = 0; loopk < PmuChannelCount; loopk++)
            {
                #region Test Config
                double ForceVoltage = -2;
                double VoltageStep = 1;
                string[] PmuPinName = { ("A" + (ChannelPmu[loopk] < 10 ? "0" : "") + ChannelPmu[loopk]) };
                int ch = ChannelPmu[loopk];
                double[] AteMeasure = new double[SampliCount];
                double[] ForceValue = new double[SampliCount];
                double[] DMMValue = new double[SampliCount];
                double[] TempValue = new double[SampliCount];

                RELAY.SwitchMode(RelayMode.Open);
                RELAY.SwitchToPPMU(PmuPinName);
                string filepath = "Slot" + SlotNum + "_PMU_" + "ch" + ChannelPmu[loopk] + "_" + "FVMV" + "_" + "Hi-Z" + "_" + "2mA" + ".csv";
                string filename = EXT_CAL_PATH + filepath;
                #endregion

                extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, ExtCaliLoad.RC_RL7, 0);//change channel
                if (loopk == 0)
                {
                    DelayHelper.Sleep(20);
                }
                
                #region Actual Test
                for (int p = 0; p < SampliCount; p++)
                {
                    PPMU.Force(PmuPinName, ForceVoltage, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);

                    Thread.Sleep(20);
                    List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), 128, 100);
                    double chResult = GetATEChannelMeasure(siList, PmuPinName);

                    double dmmRead = dmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.VOLT, 1, 7.5);

                    double[] readTemp = PPMU.ReadTemperature();
                    double chTemp = readTemp[GetPMUTempSensorIndex(ch)];

                    ForceValue[p] = ForceVoltage;
                    AteMeasure[p] = chResult;
                    DMMValue[p] = dmmRead;
                    TempValue[p] = chTemp;
                    ForceVoltage += VoltageStep;
                }
                #endregion
                
                PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);

               #region File Writing
                StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                {
                    AutoFlush = true
                };
                WriteSingleFile(sw: sw,
                                slot: SlotNum,
                                dna: arm_dna,
                                type: "PMU",
                                channel: ch,
                                mode: "FVMV",
                                rload: rload.ToString(),
                                extR: ExtBoard_Res,
                                range: "2mA",
                                ForceValue: ForceValue,
                                AteMeasure: AteMeasure,
                                DmmMeasure: DMMValue,
                                TempValue: TempValue);

                sw.Flush();
                sw.Close();

                Metadata_handler(swdata: swdata,
                                 SlotNum: SlotNum,
                                 slotList: slotList,
                                 arm_dna: arm_dna,
                                 context: context,
                                 init_Flag: false,
                                 Type: "PMU",
                                 Channel: ch,
                                 Mode: "FVMV",
                                 Rload: rload.ToString(),
                                 Range: "2mA",
                                 filepath: filepath,
                                 filetime: filetime);
                #endregion
            }

            #endregion
            

            swdata.Flush();
            swdata.Close();
            Thread.Sleep(1000);

            #region Post Process
            #region File Process
            StreamReader metareader = new StreamReader(METADATA_PATH, Encoding.UTF8);
            List<string> dnaip = new List<string>();
            List<string> path = new List<string>();
            List<string> datassingle = new List<string>();
            int cnnt = 0;
            while (!metareader.EndOfStream)
            {
                string str = metareader.ReadLine();
                if (cnnt > 6)
                {
                    if (str.Split(',')[0] == arm_dna)
                    {
                        path.Add(str);
                    }
                }
                cnnt = cnnt + 1;
            }
            metareader.Close();

            string pmurapth = EXT_CAL_PATH + context.Communicator.ServerIP + "_" + "Pmur" + ".txt";
            StreamWriter Pmur = new StreamWriter(pmurapth, true);
            Pmur.AutoFlush = true;
            #endregion
            #region Rint Calculation
            for (int p = 0; p < path.Count; p++)
            {
                string dna = path[p].Split(',')[0];
                string file = path[p].Split(',')[8];
                StreamReader singlefile = new StreamReader(EXT_CAL_PATH + file, Encoding.UTF8);
                while (!singlefile.EndOfStream)
                {
                    datassingle.Add(singlefile.ReadLine());
                }
                double RL = Convert.ToDouble(datassingle[6].Split(',')[1]);//150
                double rext = Convert.ToDouble(datassingle[8].Split(',')[1]);
                int ChannelNum = Convert.ToInt32(datassingle[4].Split(',')[1]);
                double res = 0;
                for (int linefile = 14; linefile < 19; linefile++)
                {
                    if (linefile == 16)
                    {
                        continue;
                    }
                    double ateV = Convert.ToDouble(datassingle[linefile].Split(',')[1]);
                    double voltage = Convert.ToDouble(datassingle[linefile].Split(',')[2]);
                    double iii = voltage / RL;                                  //???
                    double diff = ateV - voltage;                               
                    double rrr = diff / iii;                                    //???
                    res = res + (rrr - rext);                                   //Rint?
                }
                res = res / 4;                                                  //Average
                string ChannelFormat;
                if (ChannelNum < 10)
                {
                    ChannelFormat = "00" + Convert.ToString(ChannelNum);
                }
                else if ((ChannelNum >= 10) && (ChannelNum < 100))
                {
                    ChannelFormat = "0" + Convert.ToString(ChannelNum);
                }
                else
                {
                    ChannelFormat = Convert.ToString(ChannelNum);
                }
                Pmur.WriteLine($"ch {ChannelFormat} : {res:F3}");
                rInt[ChannelNum - 1] = res;                     //Put R_Int into array
                datassingle.Clear();
                singlefile.Close();
            }
            #endregion
            Pmur.Close();
            #endregion

            #region Thread Lock
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: false);
            #endregion
        }


        void Rint_Test(IFlowRunnerContext context, TestVersion testVersion)
        {
            #region Init Config & Variables
            List<int> ChannelDps = new List<int>();
            List<int> ChannelPmu = new List<int>();
            //-----Select PreTest or ReTest-----
            for (int m = 0; m < PmuChannelCount; m++)
            {
                ChannelPmu.Add(m + 1);
            }
            //-----get all connect slot number-----
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            //-----config Board-----
            byte[] armDnaPortCmd = new byte[2] { 14, 57 };
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd);
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;

            //---------Thread Locker--------
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: true);

            //-----Move File To History-----
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Single");

            //-----Start Write MetaData-----
            StreamWriter swdata;
            swdata = new StreamWriter(METADATA_PATH, true, Encoding.UTF8)
            {
                AutoFlush = true
            };

            Metadata_handler(
            swdata: swdata,
            SlotNum: SlotNum,
            slotList: slotList,
            arm_dna: arm_dna,
            context: context,
            init_Flag: true
            );
            #endregion

            #region Config DMM
            //-----config dmm3458A and ExtCalibrationBoard----- 
            KeysightDMM3458A dmm = new KeysightDMM3458A();
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string extConnStr = Select_IP[testVersion];
            int extPort = port;

            dmm.InitDMM(ksightConnStr);
            #endregion

            //-----Read R File-----                
            double[,] ExtBoard_Res = ReadRext(EXT_CAL_INIT_PATH + "ExtBoardRes.csv");

            extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, 1, ExternalCalibrationMode.Channel, 1, ExtCaliVI.V, ExtCaliLoad.RC_RL7, 0);   //1kΩ
            double rload = GetRloadValue(dmm, 2000, 5);
            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");


            #region The Test 

            for (int loopk = 0; loopk < PmuChannelCount; loopk++)
            {
                #region Test Config
                double ForceVoltage = -2;
                double VoltageStep = 1;
                string[] PmuPinName = { ("A" + (ChannelPmu[loopk] < 10 ? "0" : "") + ChannelPmu[loopk]) };
                int ch = ChannelPmu[loopk];
                double[] AteMeasure = new double[SampliCount];
                double[] ForceValue = new double[SampliCount];
                double[] DMMValue = new double[SampliCount];
                double[] TempValue = new double[SampliCount];

                RELAY.SwitchMode(RelayMode.Open);
                RELAY.SwitchToPPMU(PmuPinName);
                string filepath = "Slot" + SlotNum + "_PMU_" + "ch" + ChannelPmu[loopk] + "_" + "FVMV" + "_" + "Hi-Z" + "_" + "2mA" + ".csv";
                string filename = EXT_CAL_PATH + filepath;
                #endregion

                extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, ExtCaliLoad.RC_RL7, 0);//change channel
                if (loopk == 0)
                {
                    DelayHelper.Sleep(20);
                }

                #region Actual Test
                for (int p = 0; p < 1; p++)
                {
                    PPMU.Force(PmuPinName, ForceVoltage, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);

                    Thread.Sleep(20);
                    List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), 128, 100);
                    double chResult = GetATEChannelMeasure(siList, PmuPinName);

                    double dmmRead = dmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.VOLT, 1, 7.5);

                    double[] readTemp = PPMU.ReadTemperature();
                    double chTemp = readTemp[GetPMUTempSensorIndex(ch)];

                    ForceValue[p] = ForceVoltage;
                    AteMeasure[p] = chResult;
                    DMMValue[p] = dmmRead;
                    TempValue[p] = chTemp;
                    ForceVoltage += VoltageStep;
                }
                #endregion

                PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);

                #region File Writing
                StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                {
                    AutoFlush = true
                };
                WriteSingleFile(sw: sw,
                                slot: SlotNum,
                                dna: arm_dna,
                                type: "PMU",
                                channel: ch,
                                mode: "FVMV",
                                rload: rload.ToString(),
                                extR: ExtBoard_Res,
                                range: "2mA",
                                SampliCount: 1,
                                ForceValue: ForceValue,
                                AteMeasure: AteMeasure,
                                DmmMeasure: DMMValue,
                                TempValue: TempValue);

                sw.Flush();
                sw.Close();

                Metadata_handler(swdata: swdata,
                                 SlotNum: SlotNum,
                                 slotList: slotList,
                                 arm_dna: arm_dna,
                                 context: context,
                                 init_Flag: false,
                                 Type: "PMU",
                                 Channel: ch,
                                 Mode: "FVMV",
                                 Rload: rload.ToString(),
                                 Range: "2mA",
                                 filepath: filepath,
                                 filetime: filetime);
                #endregion
            }

            #endregion


            swdata.Flush();
            swdata.Close();
            Thread.Sleep(1000);

            #region Post Process
            #region File Process
            StreamReader metareader = new StreamReader(METADATA_PATH, Encoding.UTF8);
            List<string> dnaip = new List<string>();
            List<string> path = new List<string>();
            List<string> datassingle = new List<string>();
            int cnnt = 0;
            while (!metareader.EndOfStream)
            {
                string str = metareader.ReadLine();
                if (cnnt > 6)
                {
                    if (str.Split(',')[0] == arm_dna)
                    {
                        path.Add(str);
                    }
                }
                cnnt = cnnt + 1;
            }
            metareader.Close();

            string pmurapth = EXT_CAL_PATH + context.Communicator.ServerIP + "_" + "Pmur" + ".txt";
            StreamWriter Pmur = new StreamWriter(pmurapth, true);
            Pmur.AutoFlush = true;
            #endregion
            #region Rint Calculation
            for (int p = 0; p < path.Count; p++)
            {
                string dna = path[p].Split(',')[0];
                string file = path[p].Split(',')[8];
                StreamReader singlefile = new StreamReader(EXT_CAL_PATH + file, Encoding.UTF8);
                while (!singlefile.EndOfStream)
                {
                    datassingle.Add(singlefile.ReadLine());
                }
                double RL = Convert.ToDouble(datassingle[6].Split(',')[1]);//150
                double rext = Convert.ToDouble(datassingle[8].Split(',')[1]);
                int ChannelNum = Convert.ToInt32(datassingle[4].Split(',')[1]);
                double res = 0;
                for (int linefile = 14; linefile < 19; linefile++)
                {
                    if (linefile == 16)
                    {
                        continue;
                    }
                    double ateV = Convert.ToDouble(datassingle[linefile].Split(',')[1]);
                    double voltage = Convert.ToDouble(datassingle[linefile].Split(',')[2]);
                    double iii = voltage / RL;                                  //???
                    double diff = ateV - voltage;
                    double rrr = diff / iii;                                    //???
                    res = res + (rrr - rext);                                   //Rint?
                }
                res = res / 4;                                                  //Average
                string ChannelFormat;
                if (ChannelNum < 10)
                {
                    ChannelFormat = "00" + Convert.ToString(ChannelNum);
                }
                else if ((ChannelNum >= 10) && (ChannelNum < 100))
                {
                    ChannelFormat = "0" + Convert.ToString(ChannelNum);
                }
                else
                {
                    ChannelFormat = Convert.ToString(ChannelNum);
                }
                Pmur.WriteLine($"ch {ChannelFormat} : {res:F3}");
                rInt[ChannelNum - 1] = res;                     //Put R_Int into array
                datassingle.Clear();
                singlefile.Close();
            }
            #endregion
            Pmur.Close();
            #endregion

            #region Thread Lock
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: false);
            #endregion
        }

        /// <summary>
        /// Use TFTP to upload DNA/MV file into Zynq
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        void Rint_DataUpload(IFlowRunnerContext context)
        {
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            byte[] armDnaPortCmd = new byte[2] { 14, 57 }; // command to read arm dna
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd); //send command
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString(); //convert hex dna to decimal
            int SlotNum = context.Communicator.SlotNo;
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            if (SlotNum == slotList[0])
            {
                DelayHelper.Sleep(1);
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "RINT", lockFlag: true);
            }
            else
            {
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "RINT", lockFlag: true);
            }

            Thread.Sleep(10);
            var isDnaUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, RINT_COMPFILE_PATH + "DNA_" + context.Communicator.ServerIP + ".csv", FileType.dna);
            LogRawText($"Dna Status: {isDnaUploadOK}");

            Thread.Sleep(10);
            var isMVUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, RINT_COMPFILE_PATH + context.Communicator.ServerIP + "_MV.csv", FileType.mv);
            LogRawText($"MV Status: {isMVUploadOK}");

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "RINT");
        }

        /// <summary>
        /// Use TFTP to upload PMU_R(Rint) file into Zynq
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        void Pmur_Upload(IFlowRunnerContext context)
        {
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            byte[] armDnaPortCmd = new byte[2] { 14, 57 }; // command to read arm dna
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd); //send command
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString(); //convert hex dna to decimal
            int SlotNum = context.Communicator.SlotNo;
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            if (SlotNum == slotList[0])
            {
                DelayHelper.Sleep(1);
            }
            else
            {
                int slotIndex = slotList.FindIndex(x => x.Equals(SlotNum));
                while (true)
                {
                    Thread.Sleep(1000);
                    if (File.Exists(RINT_FILE_PATH + slotList[slotIndex - 1] + ".flag"))
                    {
                        File.Delete(RINT_FILE_PATH + slotList[slotIndex - 1] + ".flag");
                        break;
                    }
                }
            }
            Thread.Sleep(10);
            var isPmurUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, RINT_FILE_PATH + context.Communicator.ServerIP + "_Pmur.txt", FileType.pmu_r);
            LogRawText($"Pmur Status: {isPmurUploadOK}");
            if (SlotNum < slotList[slotList.Count - 1])
            {
                StreamWriter swSignal = new StreamWriter(RINT_FILE_PATH + SlotNum + ".flag");
                swSignal.Flush();
                swSignal.Close();
            }
        }

        /// <summary>
        /// Put Initial Files into Zynq (MV MI DNA)
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        void ExternalCalibrationReset(IFlowRunnerContext context)
        {
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            byte[] armDnaPortCmd = new byte[2] { 14, 57 }; // command to read arm dna
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd); //send command
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString(); //convert hex dna to decimal
            int SlotNum = context.Communicator.SlotNo;
            //download file to local
            if (SlotNum == slotList[0])
            {
                DelayHelper.Sleep(1);
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init", lockFlag: true);
            }
            else
            {
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init",lockFlag:true);
            }

            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            var isDnaUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, EXT_CAL_INIT_PATH + "Dna_init.csv", FileType.dna);
            LogRawText($"Dna Status: {isDnaUploadOK}");

            Thread.Sleep(10);
            var isMVUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, EXT_CAL_INIT_PATH + "MV_init.csv", FileType.mv);
            LogRawText($"MV Status: {isMVUploadOK}");

            Thread.Sleep(10);
            var isMIUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, EXT_CAL_INIT_PATH + "MI_init.csv", FileType.mi);
            LogRawText($"MI Status: {isMIUploadOK}");

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init");
        }

        /// <summary>
        /// Get External Calibration Board's Resistance Value
        /// Will Call GetRloadValue(),
        /// Will get R Value for each different Type and Mode
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        /// <param name="testVersion"></param>
        void DmmGetResValue(IFlowRunnerContext context, TestVersion testVersion)
        {
            //config DMM3458A
            KeysightDMM3458A dmm = new KeysightDMM3458A();
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string extConnStr = Select_IP[testVersion];
            int extPort = 200;
            string res_path = EXT_CAL_INIT_PATH + "res.csv";
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            byte[] armDnaPortCmd = new byte[2] { 14, 57 }; // command to read arm dna
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd); //send command
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;

            ExtCaliLoad[] RLoad_Pmu_FV = { ExtCaliLoad.RC_RL13, ExtCaliLoad.RC_RL12, ExtCaliLoad.RC_RL10, ExtCaliLoad.RC_RL8, ExtCaliLoad.RC_RL5 };
            ExtCaliLoad[] RLoad_Dps_FV = { ExtCaliLoad.RC_RL13, ExtCaliLoad.RC_RL12, ExtCaliLoad.RC_RL10, ExtCaliLoad.RC_RL8, ExtCaliLoad.RC_RL5, ExtCaliLoad.RC_RL3 };
            int PmuResChannel = 1;
            int DpsResChannel = 1;
            double[] RRange_Pmu_FV = { 10000000, 1000000, 100000, 100000, 1000 };
            double[] RRange_Dps_FV = { 1000000, 1000000, 100000, 10000, 1000, 10 };
            //Creat Directory
            if (SlotNum == slotList[0])
            {
                if (File.Exists(res_path))
                {
                    File.Delete(res_path);
                }
                DelayHelper.Sleep(1);
                dmm.InitDMM(ksightConnStr);
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init", lockFlag: true);
            }
            else
            {
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init",lockFlag:true);
            }

            Thread.Sleep(50);
            if (SlotNum == slotList[0])
            {
                double ResValue = 0;
                StreamWriter ResWriter = new StreamWriter(res_path, true, Encoding.UTF8);
                ResWriter.AutoFlush = true;
                string[] alldpsPinName = DpsPinConfig.Select_DpsPin[testVersion];
                string[] allpmuPinName = GetAllPmuPins();
                DPS.Force(alldpsPinName, 0, DpsMode.FZMV, DpsIRange._2mA, VRange.Normal);       //We Shall Force ALL DPS channel to Hi-Z
                PPMU.Force(allpmuPinName, 0, PpmuMode.FZMV, PpmuIRange._2mA, VRange.Normal);    //Just in case, Let's force ALL PMU Hi-Z

                for (int i = 0; i < RLoad_Pmu_FV.Length; i++)
                {
                    extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, PmuResChannel, ExtCaliVI.V, RLoad_Pmu_FV[i], 0);
                    if (i == 0)
                    {
                        Thread.Sleep(50000);
                    }
                    else
                    {
                        Thread.Sleep(10000);
                    }
                    ResValue = GetRloadValue(dmm, RRange_Pmu_FV[i], rLimit[i]);
                    ResWriter.Write($"Pmu_R{i + 1},{ResValue:F5}\n");
                    ResWriter.Flush();
                }

                for (int j = 0; j < RLoad_Dps_FV.Length; j++)
                {
                    extCaliHandle.SetDpsExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.DPS_FS, DpsResChannel, ExtCaliVI.V, RLoad_Dps_FV[j], 0);
                    if (j == 0)
                    {
                        Thread.Sleep(50000);
                    }
                    else
                    {
                        Thread.Sleep(10000);
                    }
                    ResValue = GetRloadValue(dmm, RRange_Dps_FV[j], rLimit[j]);
                    ResWriter.Write($"Dps_R{j + 1},{ResValue:F5}\n");
                    ResWriter.Flush();
                }
                ResWriter.Flush();
                ResWriter.Close();
                dmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.VOLT, 1, 7.5);
            }
            else
            {
                Thread.Sleep(1);
            }

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Init");
        }


        /// <summary>
        /// Main Function to Do External Instrument Calibration
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        /// <param name="testVersion"></param>
        /// <param name="isFirstTest">Flag for first test or retest</param>
        /// <param name="isPreCheck">Flag for Precheck/Postcheck</param>
        void ExternalCalibrationCollect(IFlowRunnerContext context, TestVersion testVersion, bool isFirstTest, bool isPreCheck)
        {
            #region Read JSON
            bool isDefault = Readjson(CONFIG_JSON_PATH).Default;
            List<int> Range_pmu_fvmv = Readjson(CONFIG_JSON_PATH).PMU_FVMV;
            List<int> Range_pmu_fvmi = Readjson(CONFIG_JSON_PATH).PMU_FVMI;
            List<int> Range_pmu_fimv = Readjson(CONFIG_JSON_PATH).PMU_FIMV;
            List<int> Range_pmu_fzmv = Readjson(CONFIG_JSON_PATH).PMU_FZMV;
            List<int> Range_dps_fvmv = Readjson(CONFIG_JSON_PATH).DPS_FVMV;
            List<int> Range_dps_fvmi = Readjson(CONFIG_JSON_PATH).DPS_FVMI;
            List<int> Range_dps_fimv = Readjson(CONFIG_JSON_PATH).DPS_FIMV;
            Dictionary<TestVersion, List<int>> Select_Dps = new Dictionary<TestVersion, List<int>>()
            {
                { TestVersion.Board_1K_FT, testChannelDps_1K },
                { TestVersion.Board_1K_CP, testChannelDps_1K },
                { TestVersion.Board_2K_FT, testChannelDps_2K },
                { TestVersion.Board_2K_CP, testChannelDps_2K },
                { TestVersion.Board_Ppmu_CP, testChannelDps_1K },
                { TestVersion.Board_Ppmu_FT, testChannelDps_1K },
                { TestVersion.KM_2, testChannelDps_2K }
            };
            


            List<int> ChannelDps = new List<int>();
            List<int> ChannelPmu = new List<int>();
            Dictionary<int, List<TestInfoSet>> slotTestInfo = new Dictionary<int, List<TestInfoSet>>();
            Dictionary<string, TestParaSet> testParaSet_pmu_fvmv = new Dictionary<string, TestParaSet>();
            Dictionary<string, TestParaSet> testParaSet_pmu_fvmi = new Dictionary<string, TestParaSet>();
            Dictionary<string, TestParaSet> testParaSet_pmu_fimv = new Dictionary<string, TestParaSet>();
            Dictionary<string, TestParaSet> testParaSet_pmu_fzmv = new Dictionary<string, TestParaSet>();
            Dictionary<string, TestParaSet> testParaSet_dps_fvmv = new Dictionary<string, TestParaSet>();
            Dictionary<string, TestParaSet> testParaSet_dps_fvmi = new Dictionary<string, TestParaSet>();
            Dictionary<string, TestParaSet> testParaSet_dps_fimv = new Dictionary<string, TestParaSet>();
            #endregion

            #region 配置延时，采样次数，采样间隔
            switch (testVersion)
            {
                case TestVersion.Board_1K_FT:
                    {
                        testParaSet_pmu_fvmi = avgDelays_1kft_fvmi_pmu;
                        testParaSet_dps_fvmi = avgDelays_1kft_fvmi_dps;
                        testParaSet_pmu_fimv = avgDelays_1kft_fimv_pmu;
                        testParaSet_dps_fimv = avgDelays_1kft_fimv_dps;
                    }
                    break;
                case TestVersion.Board_1K_CP:
                    {
                        testParaSet_pmu_fvmi = avgDelays_1kcp_fvmi_pmu;
                        testParaSet_dps_fvmi = avgDelays_1kcp_fvmi_dps;
                        testParaSet_pmu_fimv = avgDelays_1kcp_fimv_pmu;
                        testParaSet_dps_fimv = avgDelays_1kcp_fimv_dps;
                    }
                    break;
                case TestVersion.Board_2K_FT:
                    {
                        testParaSet_pmu_fvmi = avgDelays_2kft_fvmi_pmu;
                        testParaSet_dps_fvmi = avgDelays_2kft_fvmi_dps;
                        testParaSet_pmu_fimv = avgDelays_2kft_fimv_pmu;
                        testParaSet_dps_fimv = avgDelays_2kft_fimv_dps;
                    }
                    break;
                case TestVersion.Board_Ppmu_CP:
                    {
                        testParaSet_pmu_fvmi = avgDelays_ppmucp_fvmi_pmu;
                        testParaSet_dps_fvmi = avgDelays_ppmucp_fvmi_dps;
                        testParaSet_pmu_fimv = avgDelays_ppmucp_fimv_pmu;
                        testParaSet_dps_fimv = avgDelays_ppmucp_fimv_dps;
                    }
                    break;
                case TestVersion.Board_Ppmu_FT:
                    {
                        testParaSet_pmu_fvmi = avgDelays_ppmuft_fvmi_pmu;
                        testParaSet_dps_fvmi = avgDelays_ppmuft_fvmi_dps;
                        testParaSet_pmu_fimv = avgDelays_ppmuft_fimv_pmu;
                        testParaSet_dps_fimv = avgDelays_ppmuft_fimv_dps;
                    }
                    break;
                case TestVersion.KM_2:
                    {
                        testParaSet_pmu_fvmi = avgDelays_2km_fvmi_pmu;
                        testParaSet_dps_fvmi = avgDelays_2km_fvmi_dps;
                        testParaSet_pmu_fimv = avgDelays_2km_fimv_pmu;
                        testParaSet_dps_fimv = avgDelays_2km_fimv_dps;
                    }
                    break;
                default: break;
            }
            testParaSet_pmu_fvmv = avgDelays_fvmv_pmu;
            testParaSet_pmu_fzmv = avgDelays_fzmv_pmu;
            testParaSet_dps_fvmv = avgDelays_fvmv_dps;
            #endregion

            #region Do Configuration
            //-----get all connect slot number-----
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }

            //-----config dmm3458A and ExtCalibrationBoard----- 
            //KeysightDMM3458A dmm = new KeysightDMM3458A();
            NiVisaComms dmm = new NiVisaComms();
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string extConnStr = Select_IP[testVersion];
            int extPort = port;
            int temp = Select_Temp[testVersion];
            //-----config Board-----
            byte[] armDnaPortCmd = new byte[2] { 14, 57 };
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd);
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;

            //Get PMU_R
            string Currnet_IP_NUM = context.Communicator.ServerIP;
            string PMUR_FileName = "C:\\ProgramData\\Testrong\\ATE_Tester\\CalibrationLog\\RintCal\\PMUR\\" + Currnet_IP_NUM + "_Pmur.txt";
            double[] current_ip_pmuRint = ReadRint(PMUR_FileName);

            #endregion
            //-----Select PreTest or ReTest-----
            #region 选择第一次测试还是复测
            if (isFirstTest == true)
            {
                ChannelDps = Select_Dps[testVersion];
                for (int m = 0; m < PmuChannelCount; m++)
                {
                    ChannelPmu.Add(m + 1);
                }
                /*模式选择*/
                TestInfo.Clear();
                if (isDefault == true)//默认测试所有挡位和模式
                {
                    TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FVMV", Range = testRangesPmu, Channel = ChannelPmu });
                    TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FVMI", Range = testRangesPmu, Channel = ChannelPmu });
                    TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FIMV", Range = testRangesPmu, Channel = ChannelPmu });
                    TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FZMV", Range = testRangesPmu, Channel = ChannelPmu });
                    TestInfo.Add(new TestInfoSet { chType = "DPS", Mode = "FVMV", Range = testRangesDps, Channel = ChannelDps });
                    TestInfo.Add(new TestInfoSet { chType = "DPS", Mode = "FVMI", Range = testRangesDps, Channel = ChannelDps });
                    TestInfo.Add(new TestInfoSet { chType = "DPS", Mode = "FIMV", Range = testRangesDps, Channel = ChannelDps });
                    for (int slot = 0; slot < 12; slot++)
                    {
                        slotTestInfo.Add(slot + 1, TestInfo);
                    }
                }
                else if (isDefault == false)//测试json文件中选择的挡位和模式
                {
                    if (Range_pmu_fvmv[0] != 0)
                    {
                        TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FVMV", Range = RangeTrans(Range_pmu_fvmv), Channel = ChannelPmu });
                    }
                    if (Range_pmu_fvmi[0] != 0)
                    {
                        TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FVMI", Range = RangeTrans(Range_pmu_fvmi), Channel = ChannelPmu });
                    }
                    if (Range_pmu_fimv[0] != 0)
                    {
                        TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FIMV", Range = RangeTrans(Range_pmu_fimv), Channel = ChannelPmu });
                    }
                    if (Range_pmu_fzmv[0] != 0)
                    {
                        TestInfo.Add(new TestInfoSet { chType = "PMU", Mode = "FZMV", Range = RangeTrans(Range_pmu_fzmv), Channel = ChannelPmu });
                    }
                    if (Range_dps_fvmv[0] != 0)
                    {
                        TestInfo.Add(new TestInfoSet { chType = "DPS", Mode = "FVMV", Range = RangeTrans(Range_dps_fvmv), Channel = ChannelDps });
                    }
                    if (Range_dps_fvmi[0] != 0)
                    {
                        TestInfo.Add(new TestInfoSet { chType = "DPS", Mode = "FVMI", Range = RangeTrans(Range_dps_fvmi), Channel = ChannelDps });
                    }
                    if (Range_dps_fimv[0] != 0)
                    {
                        TestInfo.Add(new TestInfoSet { chType = "DPS", Mode = "FIMV", Range = RangeTrans(Range_dps_fimv), Channel = ChannelDps });
                    }
                    for (int slot = 0; slot < 12; slot++)
                    {
                        slotTestInfo.Add(slot + 1, TestInfo);
                    }
                }
            }
            //-----read fail log to start second test-----
            if (isFirstTest == false)
            {
                for (int slot = 0; slot < 12; slot++)
                {
                    slotTestInfo.Add(slot + 1, new List<TestInfoSet>());
                }
                TestInfo.Clear();
                ChannelDps.Clear();
                ChannelPmu.Clear();
                if (File.Exists(RETEST_LOG_PATH))
                {
                    StreamReader FailInfo = new StreamReader(RETEST_LOG_PATH, Encoding.UTF8);
                    int failLine = 0;
                    while (!FailInfo.EndOfStream)
                    {
                        string tmp = FailInfo.ReadLine();
                        if (failLine > 0)
                        {
                            int failSlot = Convert.ToInt16(tmp.Split(',')[0]);
                            string failType = tmp.Split(',')[1];
                            string failMode = tmp.Split(',')[2];
                            List<string> failRange = new List<string>();
                            failRange.Add(tmp.Split(',')[3]);
                            List<int> failChannel = new List<int>();
                            string failSet = tmp.Split(',')[4];
                            string[] failChSet = failSet.Split('_');
                            for (int failCount = 0; failCount < failChSet.Length; failCount++)
                            {
                                failChannel.Add(Convert.ToInt32(failChSet[failCount]));
                            }
                            slotTestInfo[failSlot].Add(new TestInfoSet { chType = failType, Mode = failMode, Range = failRange, Channel = failChannel });
                        }
                        failLine++;
                    }
                    FailInfo.Close();
                }
            }
            #endregion
            //-----Read R File-----                
            Dictionary<string, string> RlPmuFv = ReadRload(EXT_CAL_INIT_PATH + "res.csv")[0];
            Dictionary<string, string> RlPmuFi = ReadRload(EXT_CAL_INIT_PATH + "res.csv")[1];
            Dictionary<string, string> RlDpsFv = ReadRload(EXT_CAL_INIT_PATH + "res.csv")[2];
            Dictionary<string, string> RlDpsFi = ReadRload(EXT_CAL_INIT_PATH + "res.csv")[3];
            double[,] ExtBoard_Res = ReadRext(EXT_CAL_INIT_PATH + "ExtBoardRes.csv");

            #region File/Folder Prepartion
            //---------Thread Locker--------
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: true);

            //-----Move File To History-----
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Normal", isPreCheck: isPreCheck);

            //-----Start Slot Number-----
            // Write MetaData.csv Header
            StreamWriter swdata;
            swdata = new StreamWriter(METADATA_PATH, true, Encoding.UTF8)
            {
                AutoFlush = true
            };

            Metadata_handler(
                swdata: swdata,
                SlotNum: SlotNum,
                slotList: slotList,
                arm_dna: arm_dna,
                context: context,
                init_Flag: true
                );

            #endregion

            #region Data Collection
            //-----Start Data Collection-----
            dmm.Init(ksightConnStr);
            List<TestInfoSet> Info = slotTestInfo[SlotNum];
            //{0:PMU_FVMV; 1:PMU_FVMI; 2:PMU_FIMV; 3:PMU_FZMV; 4:DPS_FVMV; 5:DPS_FVMI; 6:DPS_FIMV}
            for (int loopi = 0; loopi < Info.Count/*Info.Count*/; loopi++)//-----Loop Mode and Type-----
            {
                string Type = Info[loopi].chType;
                string Mode = Info[loopi].Mode;
                List<string> ListRanges = Info[loopi].Range;
                List<int> ListChannels = Info[loopi].Channel;
                //{0:5uA; 1:20uA; 2:200uA; 3:2mA; 4:60mA; 5:1A}
                for (int loopj = 0; loopj < ListRanges.Count/*ListRanges.Count*/; loopj++)//-----Loop Range-----
                {
                    dmm.ClearReadingMemory();//Reset Dmm
                    dmm.ResetInstrument();
                    string Range = ListRanges[loopj];
                    if (Range == "1A" && Mode == "FIMV")
                    {
                        continue;
                    }
                    Dictionary<int, double[]> AteMeasureDir = new Dictionary<int, double[]>();
                    Dictionary<int, double[]> ForceValueDir = new Dictionary<int, double[]>();
                    Dictionary<int, double[]> DmmMeasureDir = new Dictionary<int, double[]>();
                    Dictionary<int, double[]> TempValueDir = new Dictionary<int, double[]>();


                    List<int> testCh = new List<int>();
                    ExtCaliLoad Rcut = (Mode == "FVMV") ? ExtCaliLoad.no_load : Rcut_MIFI[Range];
                    string Rload = (Mode == "FVMV" || Mode == "FZMV") ? "Hi-Z" : strRloadFvmi[Range];
                    string rl = "";
                    if (Mode == "FVMV" || Mode == "FZMV")
                    {
                        rl = "Hi-Z";
                    }
                    else
                    {
                        if (Type == "PMU")
                        {
                            rl = (Mode == "FVMI") ? RlPmuFv[Range] : RlPmuFi[Range];
                        }
                        else if (Type == "DPS")
                        {
                            rl = (Mode == "FVMI") ? RlDpsFv[Range] : RlDpsFi[Range];
                        }
                    }
                    switch (Mode)
                    {
                        case "FVMV":
                            {
                                dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 7.5, 0.04);
                            }
                            break;
                        case "FVMI":
                            {
                                if (Type == "PMU")
                                {
                                    if (Range == "60mA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.CURR, DmmCurrRanges[Range], 1);       //Current Measuring
                                    }
                                    else
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 7.5, 0.04);
                                    }
                                }
                                else
                                {
                                    if (Range == "60mA" || Range == "1A")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.CURR, DmmCurrRanges[Range], 1);       //Current Measuring
                                    }
                                    else
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 7.5, 0.04);
                                    }
                                }
                            }
                            break;
                        case "FZMV":
                            {
                                dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 7.5, 0.04);
                            }
                            break;
                        case "FIMV":
                            {
                                if (Type == "PMU")
                                {
                                    if (Range == "60mA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 0.04);
                                    }
                                    else if (Range == "5uA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 1);
                                    }
                                    else if (Range == "20uA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 1);
                                    }
                                    else if (Range == "200uA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 1);
                                    }
                                    else
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 0.04);
                                    }
                                }
                                else
                                {
                                    if (Range == "60mA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 0.04);
                                    }
                                    else if (Range == "5uA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 1);
                                    }
                                    else if (Range == "20uA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 2);
                                    }
                                    else if (Range == "200uA")
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 1);
                                    }
                                    else
                                    {
                                        dmm.Setup(NiVisaComms.Dmm3458AMeasureMode.VOLT, 5, 0.04);
                                    }
                                }
                            }
                            break;
                        default: break;
                    }
                    string[] PmuPinName_FZ = new string[1];
                    string[] PmuPinName_FV = new string[1];
                    string[] PmuPinName_FZFV = new string[2];


                    #region Do Force/Measure/DMM
                    for (int loopk = 0; loopk < ListChannels.Count/*ListChannels.Count*/; loopk++)//-----Loop Channel-----
                    {
                        //Note: Must put them here as Dictionary `Add` do reference NOT clone
                        double[] AteMeasure = new double[SampliCount];
                        double[] ForceValue = new double[SampliCount];
                        double[] TempValue = new double[SampliCount];

                        if (Type == "PMU")
                        {
                            int ch = ListChannels[loopk];

                            string[] PmuPinName = { ("A" + (ListChannels[loopk] < 10 ? "0" : "") + ListChannels[loopk]) };
                            PmuPinName_FZ[0] = ("A" + (ListChannels[loopk] < 10 ? "0" : "") + ListChannels[loopk]);
                            if ((ListChannels[loopk] % 8 >= 1) && (ListChannels[loopk] % 8 <= 4))
                            {
                                PmuPinName_FV[0] = ("A" + ((ListChannels[loopk] + 4) < 10 ? "0" : "") + (ListChannels[loopk] + 4));
                            }
                            else if ((ListChannels[loopk] % 8 > 4) || (ListChannels[loopk] % 8 == 0))//kChannel == 4, 12
                            {
                                PmuPinName_FV[0] = ("A" + ((ListChannels[loopk] - 4) < 10 ? "0" : "") + (ListChannels[loopk] - 4));
                            }
                            //PmuPinName_FV[0] = FZMV_PMU[PmuPinName_FZ[0]];
                            PmuPinName_FZFV[0] = PmuPinName_FZ[0];
                            PmuPinName_FZFV[1] = PmuPinName_FV[0];
                            RELAY.SwitchMode(RelayMode.Open);
                            if (ModesPmu[Mode] == PpmuMode.FZMV)
                            {
                                RELAY.SwitchToPPMU(PmuPinName_FZFV);
                            }
                            else
                            {
                                RELAY.SwitchToPPMU(PmuPinName);
                            }
                            double ForceVoltage = VoltageInitialDefault;
                            double VoltageStep = VoltageStepDefault;
                            if (ModesPmu[Mode] == PpmuMode.FVMI)
                            {
                                if (RangesPmu[Range] == PpmuIRange._60mA || RangesPmu[Range] == PpmuIRange._5uA)
                                {
                                    ForceVoltage = VoltageInitialSet;
                                    VoltageStep = VoltageStepSet;
                                }
                                if (RangesPmu[Range] == PpmuIRange._20uA)
                                {
                                    ForceVoltage = VoltageInitialSet;
                                }
                            }
                            switch (Info[loopi].Mode)
                            {
                                case "FVMV":
                                    {
                                        extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, Rcut, 0);//change channel
                                        Thread.Sleep(5);
                                        for (int p = 0; p < SampliCount; p++)
                                        {
                                            PPMU.Force(PmuPinName, ForceVoltage, ModesPmu[Mode], RangesPmu[Range], VRange.Normal);
                                            Thread.Sleep(1);
                                            PPMU.Force(PmuPinName, ForceVoltage, ModesPmu[Mode], RangesPmu[Range], VRange.Normal);
                                            Thread.Sleep(testParaSet_pmu_fvmv[Range].delayMs);
                                            dmm.TriggerSingleMeasure();
                                            List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), testParaSet_pmu_fvmv[Range].avgTimes, testParaSet_pmu_fvmv[Range].samDelay);
                                            double chResult = GetATEChannelMeasure(siList, PmuPinName);
                                            double[] readTemp = PPMU.ReadTemperature();
                                            double chTemp = readTemp[GetPMUTempSensorIndex(ch)];
                                            TempValue[p] = chTemp;
                                            AteMeasure[p] = chResult;
                                            ForceValue[p] = ForceVoltage;
                                            ForceVoltage += VoltageStep;
                                        }
                                        PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, RangesPmu[Range], VRange.Normal);
                                        Thread.Sleep(5);
                                    }
                                    break;
                                case "FVMI":
                                    {
                                        if (RangesPmu[Range] == PpmuIRange._60mA)
                                        {
                                            extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.I, Rcut, 0);
                                            Thread.Sleep(15);
                                            for (int p = 0; p < SampliCount; p++)
                                            {
                                                PPMU.Force(PmuPinName, ForceVoltage, ModesPmu[Mode], RangesPmu[Range], VRange.Normal);
                                                Thread.Sleep(testParaSet_pmu_fvmi[Range].delayMs);
                                                dmm.TriggerSingleMeasure();
                                                Thread.Sleep(50);
                                                List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMI"), testParaSet_pmu_fvmi[Range].avgTimes, testParaSet_pmu_fvmi[Range].samDelay);
                                                double chResult = GetATEChannelMeasure(siList, PmuPinName);
                                                double[] readTemp = PPMU.ReadTemperature();
                                                double chTemp = readTemp[GetPMUTempSensorIndex(ch)];
                                                TempValue[p] = chTemp;
                                                AteMeasure[p] = chResult;
                                                ForceValue[p] = ForceVoltage / (Convert.ToDouble(RlPmuFv[Range]) + ExtBoard_Res[ch - 1, SlotNum - 1]);
                                                ForceVoltage += VoltageStep;
                                            }
                                        }
                                        else
                                        {
                                            extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, Rcut, 0);
                                            Thread.Sleep(5);
                                            if (loopk == 0)
                                            {
                                                Thread.Sleep(5);
                                            }
                                            for (int p = 0; p < SampliCount; p++)
                                            {
                                                PPMU.Force(PmuPinName, ForceVoltage, ModesPmu[Mode], RangesPmu[Range], VRange.Normal);
                                                Thread.Sleep(testParaSet_pmu_fvmi[Range].delayMs);
                                                dmm.TriggerSingleMeasure();
                                                List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMI"), testParaSet_pmu_fvmi[Range].avgTimes, testParaSet_pmu_fvmi[Range].samDelay);
                                                double chResult = GetATEChannelMeasure(siList, PmuPinName);
                                                double[] readTemp = PPMU.ReadTemperature();
                                                double chTemp = readTemp[GetPMUTempSensorIndex(ch)];
                                                TempValue[p] = chTemp;
                                                AteMeasure[p] = chResult;
                                                ForceValue[p] = ForceVoltage / (Convert.ToDouble(RlPmuFv[Range]) + ExtBoard_Res[ch - 1, SlotNum - 1]);
                                                if (RangesPmu[Range] == PpmuIRange._20uA)
                                                {
                                                    ForceVoltage += VoltageStep20uA[p];
                                                }
                                                else
                                                {
                                                    ForceVoltage += VoltageStep;
                                                }
                                            }
                                        }
                                        PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, RangesPmu[Range], VRange.Normal);
                                        Thread.Sleep(10);
                                    }
                                    break;
                                case "FIMV":
                                    {
                                        extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, Rcut, 0);
                                        Thread.Sleep(5);
                                        for (int p = 0; p < SampliCount; p++)
                                        {
                                            double ForceCurrent = FiRanges[Range] * CurrScale[p];//Force Current                                           
                                            PPMU.Force(PmuPinName, ForceCurrent, ModesPmu[Mode], RangesPmu[Range], VRange.Normal);
                                            Thread.Sleep(testParaSet_pmu_fimv[Range].delayMs);
                                            dmm.TriggerSingleMeasure();
                                            if (Range == "5uA" || Range == "20uA")
                                            {
                                                if (loopk == 0 && p == 0)
                                                {
                                                    Thread.Sleep(50);
                                                }
                                                Thread.Sleep(80);
                                            }
                                            if (Range == "200uA")
                                            {
                                                Thread.Sleep(50);
                                            }
                                            List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FIMV"), testParaSet_pmu_fimv[Range].avgTimes, testParaSet_pmu_fimv[Range].samDelay);
                                            double chResult = GetATEChannelMeasure(siList, PmuPinName);
                                            double Real_V = 0;
                                            double ExtRload = Convert.ToDouble(RlPmuFi[Range]);
                                        
                                            Real_V = chResult + ForceCurrent * current_ip_pmuRint[ListChannels[loopk] - 1];
                                            double Total_Rint = current_ip_pmuRint[ListChannels[loopk] - 1] + ExtBoard_Res[ListChannels[loopk] - 1, SlotNum - 1];
                                            double Real_I = Real_V / (Total_Rint + ExtRload);
                                            AteMeasure[p] = (Real_V - (Total_Rint * Real_I)) / ExtRload;
                                            //AteMeasure[p] = chResult / (Convert.ToDouble(RlPmuFi[Range]) + ExtBoard_Res[ch - 1, SlotNum - 1]);
                                            ForceValue[p] = ForceCurrent;
                                            double[] readTemp = PPMU.ReadTemperature();
                                            double chTemp = readTemp[GetPMUTempSensorIndex(ch)];
                                            TempValue[p] = chTemp;
                                        }
                                        PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, RangesPmu[Range], VRange.Normal);
                                        Thread.Sleep(10);
                                    }
                                    break;
                                case "FZMV":
                                    {
                                        extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.V, ExtCaliLoad.no_load, 0);
                                        Thread.Sleep(5);
                                        for (int p = 0; p < SampliCount; p++)
                                        {
                                            PPMU.Force(PmuPinName_FV, ForceVoltage, PpmuMode.FVMV, RangesPmu[Range], VRange.Normal);
                                            Thread.Sleep(1);
                                            PPMU.Force(PmuPinName_FV, ForceVoltage, PpmuMode.FVMV, RangesPmu[Range], VRange.Normal);
                                            PPMU.Force(PmuPinName_FZ, ForceVoltage, PpmuMode.FZMV, RangesPmu[Range], VRange.Normal);
                                            Thread.Sleep(testParaSet_pmu_fzmv[Range].delayMs);
                                            dmm.TriggerSingleMeasure();
                                            List<SiteInfo> siList = PPMU.Measure(PmuPinName_FZ, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), testParaSet_pmu_fzmv[Range].avgTimes, testParaSet_pmu_fzmv[Range].samDelay);
                                            double chResult = GetATEChannelMeasure(siList, PmuPinName_FZ);
                                            double[] readTemp = PPMU.ReadTemperature();
                                            double chTemp = readTemp[GetPMUTempSensorIndex(ch)];
                                            TempValue[p] = chTemp;
                                            AteMeasure[p] = chResult;
                                            ForceValue[p] = ForceVoltage;
                                            ForceVoltage += VoltageStep;
                                        }
                                        PPMU.Force(PmuPinName_FV, 0, PpmuMode.FVMV, RangesPmu[Range], VRange.Normal);
                                        PPMU.Force(PmuPinName_FZ, 0, PpmuMode.FVMV, RangesPmu[Range], VRange.Normal);
                                        Thread.Sleep(5);
                                        PPMU.Force(PmuPinName_FV, 0, PpmuMode.FZMV, RangesPmu[Range], VRange.Normal);
                                        PPMU.Force(PmuPinName_FZ, 0, PpmuMode.FZMV, RangesPmu[Range], VRange.Normal);
                                        Thread.Sleep(5);
                                    }
                                    break;
                                default: break;
                            }
                            AteMeasureDir.Add(ch, AteMeasure);
                            ForceValueDir.Add(ch, ForceValue);
                            TempValueDir.Add(ch, TempValue);
                            testCh.Add(ch);
                        }
                        else if (Type == "DPS")
                        {
                            string[] DpsPinName = { ("DPS" + ListChannels[loopk]) };
                            string[] allDpsPinNames = DpsPinConfig.Select_DpsPin[testVersion];
                            double ForceVoltage = (RangesDps[Range] == DpsIRange._1A) ? VoltageInitialDps1A : VoltageInitialDefault;//1A for range
                            double VoltageStep = (RangesDps[Range] == DpsIRange._1A) ? VoltageStepDps1A : VoltageStepDefault;
                            if (ModesDps[Mode] == DpsMode.FVMI)
                            {
                                if (RangesDps[Range] != DpsIRange._1A)
                                {
                                    ForceVoltage = VoltageInitialSet;
                                    VoltageStep = VoltageStepSet;
                                }
                            }
                            int ch = ListChannels[loopk];

                            DpsRangeRelay.SetDpsRangeRelayBySignals(allDpsPinNames, DpsRelayState.OPEN, context);
                            switch (RangesDps[Range])
                            {
                                case DpsIRange._60mA:
                                    {
                                        DpsRangeRelay.SetDpsRangeRelayBySignals(DpsPinName, DpsRelayState._60MA, context);
                                    }
                                    break;
                                case DpsIRange._1A:
                                    {
                                        DpsRangeRelay.SetDpsRangeRelayBySignals(DpsPinName, DpsRelayState.EXT, context);
                                    }
                                    break;
                                default:
                                    {
                                        DpsRangeRelay.SetDpsRangeRelayBySignals(DpsPinName, DpsRelayState.INT, context);
                                    }
                                    break;
                            }
                            switch (Info[loopi].Mode)
                            {
                                case "FVMV":
                                    {
                                        extCaliHandle.SetDpsExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.DPS_FS, ch, ExtCaliVI.V, Rcut, 0);//change channel
                                        Thread.Sleep(10);
                                        for (int p = 0; p < SampliCount; p++)
                                        {
                                            DPS.Force(DpsPinName, ForceVoltage, ModesDps[Mode], RangesDps[Range], VRange.Normal);
                                            Thread.Sleep(testParaSet_dps_fvmv[Range].delayMs);
                                            if ((ListChannels[loopk] == 2 || ListChannels[loopk] == 3) && testVersion == TestVersion.Board_2K_FT)
                                            {
                                                Thread.Sleep(50);
                                            }
                                            dmm.TriggerSingleMeasure();
                                            List<SiteInfo> siList = DPS.Measure(DpsPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), testParaSet_dps_fvmv[Range].avgTimes, testParaSet_dps_fvmv[Range].samDelay);
                                            double chResult = GetATEChannelMeasure(siList, DpsPinName);
                                            double[] readTemp = DPS.ReadTemperature();
                                            int TempIndex = GetDPSTempSensorIndex(ListChannels[loopk]);
                                            double chTemp;
                                            if (TempIndex > readTemp.Length  - 1 )
                                            {
                                                chTemp = -65535;
                                            }
                                            else
                                            {
                                                chTemp = readTemp[TempIndex];
                                            }
                                            TempValue[p] = chTemp;
                                            ForceValue[p] = ForceVoltage;
                                            AteMeasure[p] = chResult;
                                            ForceVoltage += VoltageStep;
                                        }
                                        DPS.Force(DpsPinName, 0, DpsMode.FVMV, RangesDps[Range], VRange.Normal);
                                        Thread.Sleep(5);
                                    }
                                    break;
                                case "FVMI":
                                    {
                                        if ((RangesDps[Range] == DpsIRange._60mA) || (RangesDps[Range] == DpsIRange._1A))
                                        {
                                            extCaliHandle.SetDpsExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.DPS_FS, ch, ExtCaliVI.I, Rcut, 0);
                                            Thread.Sleep(20);
                                            for (int p = 0; p < SampliCount; p++)
                                            {
                                                DPS.Force(DpsPinName, ForceVoltage, ModesDps[Mode], RangesDps[Range], VRange.Normal);
                                                double CurrValue = ForceVoltage / Convert.ToDouble(RlDpsFv[Range]);
                                                Thread.Sleep(testParaSet_dps_fvmi[Range].delayMs);
                                                if (loopk == 0 || p == 0)
                                                {
                                                    Thread.Sleep(100);
                                                }
                                                dmm.TriggerSingleMeasure();
                                                Thread.Sleep(50);
                                                List<SiteInfo> siList = DPS.Measure(DpsPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMI"), testParaSet_dps_fvmi[Range].avgTimes, testParaSet_dps_fvmi[Range].samDelay);
                                                double chResult = GetATEChannelMeasure(siList, DpsPinName);
                                                double[] readTemp = DPS.ReadTemperature();
                                                int TempIndex = GetDPSTempSensorIndex(ListChannels[loopk]);
                                                double chTemp;
                                                if (TempIndex > readTemp.Length  - 1 )
                                                {
                                                    chTemp = -65535;
                                                }
                                                else
                                                {
                                                    chTemp = readTemp[TempIndex];
                                                }
                                                TempValue[p] = chTemp;
                                                ForceValue[p] = CurrValue;
                                                AteMeasure[p] = chResult;
                                                ForceVoltage += VoltageStep;
                                            }
                                        }
                                        else
                                        {
                                            extCaliHandle.SetDpsExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.DPS_FS, ch, ExtCaliVI.V, Rcut, 0);
                                            Thread.Sleep(20);
                                            for (int p = 0; p < SampliCount; p++)
                                            {
                                                DPS.Force(DpsPinName, ForceVoltage, ModesDps[Mode], RangesDps[Range], VRange.Normal);
                                                double CurrValue = ForceVoltage / Convert.ToDouble(RlDpsFv[Range]);
                                                Thread.Sleep(testParaSet_dps_fvmi[Range].delayMs);
                                                dmm.TriggerSingleMeasure();
                                                if (p == 0)
                                                {
                                                    if (Range == "5uA")
                                                    {
                                                        Thread.Sleep(10);
                                                    }
                                                    else if (Range == "20uA")
                                                    {
                                                        Thread.Sleep(50);
                                                    }
                                                    else if (Range == "200uA")
                                                    {
                                                        Thread.Sleep(100);
                                                    }
                                                    else
                                                    {
                                                        Thread.Sleep(10);
                                                    }
                                                }
                                                List<SiteInfo> siList = DPS.Measure(DpsPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMI"), testParaSet_dps_fvmi[Range].avgTimes, testParaSet_dps_fvmi[Range].samDelay);
                                                double chResult = GetATEChannelMeasure(siList, DpsPinName);
                                                double[] readTemp = DPS.ReadTemperature();
                                                int TempIndex = GetDPSTempSensorIndex(ListChannels[loopk]);
                                                double chTemp;
                                                if (TempIndex > readTemp.Length  - 1 )
                                                {
                                                    chTemp = -65535;
                                                }
                                                else
                                                {
                                                    chTemp = readTemp[TempIndex];
                                                }
                                                TempValue[p] = chTemp;
                                                ForceValue[p] = CurrValue;
                                                AteMeasure[p] = chResult;
                                                ForceVoltage += VoltageStep;
                                            }
                                        }
                                        DPS.Force(DpsPinName, 0, DpsMode.FVMV, RangesDps[Range], VRange.Normal);
                                        Thread.Sleep(10);
                                    }
                                    break;
                                case "FIMV":
                                    {
                                        extCaliHandle.SetDpsExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.DPS_FS, ch, ExtCaliVI.V, Rcut, 0);
                                        Thread.Sleep(10);
                                        for (int p = 0; p < SampliCount; p++)
                                        {
                                            double ForceCurrent = FiRanges[Range] * CurrScale[p];//Force Current                                                                                                    
                                            DPS.Force(DpsPinName, ForceCurrent, ModesDps[Mode], RangesDps[Range], VRange.Normal);
                                            Thread.Sleep(testParaSet_dps_fimv[Range].delayMs);
                                            if (Range == "5uA" || Range == "20uA")
                                            {
                                                if (ListChannels[loopk] == 33 || ListChannels[loopk] == 1)
                                                {
                                                    if (Range == "20uA")
                                                    {
                                                        Thread.Sleep(30);
                                                    }
                                                    if (Range == "5uA")
                                                    {
                                                        Thread.Sleep(50);
                                                    }
                                                }
                                            }
                                            dmm.TriggerSingleMeasure();
                                            if (Range == "5uA" || Range == "20uA" || Range == "200uA")
                                            {
                                                if (p == 0)
                                                {
                                                    Thread.Sleep(50);
                                                }
                                                if (Range == "5uA")
                                                {
                                                    Thread.Sleep(25);
                                                }
                                                else if (Range == "20uA")
                                                {
                                                    Thread.Sleep(50);
                                                }
                                                else if (Range == "200uA")
                                                {
                                                    Thread.Sleep(50);
                                                }
                                            }
                                            List<SiteInfo> siList = DPS.Measure(DpsPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FIMV"), testParaSet_dps_fimv[Range].avgTimes, testParaSet_dps_fimv[Range].samDelay);
                                            double chResult = GetATEChannelMeasure(siList, DpsPinName);
                                            double[] readTemp = DPS.ReadTemperature();
                                            int TempIndex = GetDPSTempSensorIndex(ListChannels[loopk]);
                                            double chTemp;
                                            if (TempIndex > readTemp.Length  - 1 )
                                            {
                                                chTemp = -65535;
                                            }
                                            else
                                            {
                                                chTemp = readTemp[TempIndex];
                                            }
                                            TempValue[p] = chTemp;
                                            ForceValue[p] = ForceCurrent;
                                            AteMeasure[p] = chResult / Convert.ToDouble(RlDpsFi[Range]);
                                        }
                                        DPS.Force(DpsPinName, 0, DpsMode.FZMV, RangesDps[Range], VRange.Normal);
                                        Thread.Sleep(10);
                                    }
                                    break;
                                default: break;
                            }
                            AteMeasureDir.Add(ch, AteMeasure);
                            ForceValueDir.Add(ch, ForceValue);
                            TempValueDir.Add(ch, TempValue);
                            testCh.Add(ch);
                        }
                    }


                    //Read Back Value From DMM
                    int DataCount = testCh.Count * SampliCount;
                    double[] dmmRead = dmm.MultiRead(DataCount);
                    dmm.ClearReadingMemory();
                    DmmMeasureDir = ReadBackDmm(dmmRead, testCh);
                    #endregion

                    #region WriteToFile
                    //Write Data to File
                    if (Type == "PMU")
                    {
                        for (int writeNum = 0; writeNum < testCh.Count; writeNum++)
                        {
                            int ch = testCh[writeNum];
                            string filepath = "Slot" + SlotNum + "_PMU_" + "ch" + ch + "_" + Mode + "_" + Rload + "_" + Range + ".csv";
                            string filename = EXT_CAL_PATH + filepath;
                            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");

                            StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                            {
                                AutoFlush = true
                            };

                            WriteSingleFile(sw: sw,
                                            slot: SlotNum,
                                            dna: arm_dna,
                                            type: Type,
                                            channel: ch,
                                            mode: Mode,
                                            rload: rl,
                                            extR: ExtBoard_Res,
                                            range: Range,
                                            SampliCount: SampliCount,
                                            ForceValue: ForceValueDir[ch],
                                            AteMeasure: AteMeasureDir[ch],
                                            DmmMeasure: DmmMeasureDir[ch],
                                            TempValue: TempValueDir[ch]);

                            sw.Flush();
                            sw.Close();

                            Metadata_handler(swdata: swdata,
                                             SlotNum: SlotNum,
                                             slotList: slotList,
                                             arm_dna: arm_dna,
                                             context: context,
                                             init_Flag: false,
                                             Type: Type,
                                             Channel: ch,
                                             Mode: Mode,
                                             Rload: rl,
                                             Range: Range,
                                             filepath: filepath,
                                             filetime: filetime);
                        }
                    }
                    else if (Type == "DPS")
                    {
                        for (int writeNum = 0; writeNum < testCh.Count; writeNum++)
                        {
                            int ch = testCh[writeNum];
                            string filepath = "Slot" + SlotNum + "_DPS_" + "ch" + ch + "_" + Mode + "_" + Rload + "_" + Range + ".csv";
                            string filename = EXT_CAL_PATH + filepath;
                            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
                            double[,] ZeroExtR = {
                                { 0.0 , 0.0 , 0.0}
                            };

                            StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                            {
                                AutoFlush = true
                            };

                            WriteSingleFile(sw: sw,
                                            slot: SlotNum,
                                            dna: arm_dna,
                                            type: Info[loopi].chType,
                                            channel: ch,
                                            mode: Mode,
                                            rload: rl,
                                            extR: ZeroExtR,
                                            range: Range,
                                            SampliCount:SampliCount,
                                            ForceValue: ForceValueDir[ch],
                                            AteMeasure: AteMeasureDir[ch],
                                            DmmMeasure: DmmMeasureDir[ch],
                                            TempValue: TempValueDir[ch]);

                            sw.Flush();
                            sw.Close();

                            Metadata_handler(swdata: swdata,
                                             SlotNum: SlotNum,
                                             slotList: slotList,
                                             arm_dna: arm_dna,
                                             context: context,
                                             init_Flag: false,
                                             Type: Type,
                                             Channel: ch,
                                             Mode: Mode,
                                             Rload: rl,
                                             Range: Range,
                                             filepath: filepath,
                                             filetime: filetime);
                        }
                    }
                    #endregion
                }
            }
            #endregion

            #region Thread Lock
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL");
            #endregion

            dmm.ResetInstrument();
            swdata.Flush();
            swdata.Close();

        }

        /// <summary>
        /// Use TFTP to upload DNA/MV/MI file into Zynq 
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        void ExternalCalibrationWriteCalFiles(IFlowRunnerContext context)
        {
            //read dna and ip
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            byte[] armDnaPortCmd = new byte[2] { 14, 57 }; // command to read arm dna
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd); //send command
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString(); //convert hex dna to decimal
            int SlotNum = context.Communicator.SlotNo;
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            if (SlotNum == slotList[0])
            {
                DelayHelper.Sleep(1);
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_COM", lockFlag: true);
            }
            else
            {
                SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_COM", lockFlag: true);
            }

            //Write files
            Thread.Sleep(10);
            var isDnaUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, CAL_COMPFILE_PATH + "DNA_" + context.Communicator.ServerIP + ".csv", FileType.dna);
            LogRawText($"Dna Status: {isDnaUploadOK}");

            Thread.Sleep(10);
            var isMVUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, CAL_COMPFILE_PATH + context.Communicator.ServerIP + "_MV.csv", FileType.mv);
            LogRawText($"MV Status: {isMVUploadOK}");

            Thread.Sleep(10);
            var isMIUploadOK = extCaliHandle.UploadFile(context.Communicator.ServerIP, CAL_COMPFILE_PATH + context.Communicator.ServerIP + "_MI.csv", FileType.mi);
            LogRawText($"MI Status: {isMIUploadOK}");

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_COM");
        }


        /// <summary>
        /// Get Measurments For Rint w/ GND Board
        /// Only Use FVMI 2mA Range
        /// </summary>
        /// <param name="context">info from ATE Software</param>
        void Rint_GND_FVMI_2mA(IFlowRunnerContext context)
        {
            List<int> ChannelPmu = new List<int>();
            for (int m = 0; m < PmuChannelCount; m++)
            {
                ChannelPmu.Add(m + 1);
            }
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            //-----config Board-----
            byte[] armDnaPortCmd = new byte[2] { 14, 57 };
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd);
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;
            double[,] ExtBoard_Res = ReadRext(EXT_CAL_INIT_PATH + "ExtBoardRes.csv");

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: true);

            //Folder Related
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Single");

            //-----Start Slot Number-----
            StreamWriter swdata;
            swdata = new StreamWriter(METADATA_PATH, true, Encoding.UTF8)
            {
                AutoFlush = true
            };
            Metadata_handler(
                swdata: swdata,
                SlotNum: SlotNum,
                slotList: slotList,
                arm_dna: arm_dna,
                context: context,
                init_Flag: true
            );
            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
            for (int loopk = 0; loopk < PmuChannelCount; loopk++)
            {
                string[] PmuPinName = { ("A" + (ChannelPmu[loopk] < 10 ? "0" : "") + ChannelPmu[loopk]) };
                RELAY.SwitchMode(RelayMode.Open);
                RELAY.SwitchToPPMU(PmuPinName);
                double ForceCurrent = -0.001;//1mA
                double CurrentStep = 0.0005;
                double ForceV = -0.008;
                double Vstep = 0.0004;
                string filepath = "Slot" + SlotNum + "_PMU_" + "ch" + ChannelPmu[loopk] + "_" + "FVMI" + "_" + "Hi-Z" + "_" + "2mA" + ".csv";
                string filename = EXT_CAL_PATH + filepath;
                int ch = ChannelPmu[loopk];
                double[] AteMeasure = new double[SampliCount];
                double[] ForceValue = new double[SampliCount];
                double[] DMMValue = new double[SampliCount];
                double[] TempValue = new double[SampliCount];
                double[] customData = new double[65535];
                StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                {
                    AutoFlush = true
                };

                if (loopk == 0)
                {
                    DelayHelper.Sleep(20);
                }
                //Force 0V Measure Voltage
                PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);
                List<SiteInfo> zero_V_List = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), 128, 100);
                double zeroVResult = GetATEChannelMeasure(zero_V_List, PmuPinName);
                //sw.Write($"Force_0V_MV={zeroVResult * 1000:F8}mV\n");
                customData[0] = zeroVResult;

                //Force 0V Measure Current
                PPMU.Force(PmuPinName, 0, PpmuMode.FVMI, PpmuIRange._2mA, VRange.Normal);
                List<SiteInfo> zero_I_List = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMI"), 128, 100);
                double zeroIResult = GetATEChannelMeasure(zero_I_List, PmuPinName);
                //sw.Write($"Force_0V_MI={zeroIResult * 1000:F8}mA\n");
                customData[1] = zeroIResult;

                sw.Write("Force Voltage(mV),Measure Voltage(mV),Measure Current(mA),Diff_Voltage(mV),Resistance(FV/MI),Resistance(Caled)\n");

                for (int p = 0; p < 50; p++)
                {
                    PPMU.Force(PmuPinName, ForceV, PpmuMode.FVMI, PpmuIRange._2mA, VRange.Normal);
                    
                    Thread.Sleep(20);
                    List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMI"), 128, 100);
                    double chResult = GetATEChannelMeasure(siList, PmuPinName);

                    PPMU.Force(PmuPinName, ForceV, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);
                    List<SiteInfo> svList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), 128, 100);
                    double chVResult = GetATEChannelMeasure(svList, PmuPinName);
                    double[] readTemp = PPMU.ReadTemperature();
                    double chTemp = readTemp[GetPMUTempSensorIndex(ch)];

                    ForceValue[p] = ForceV;
                    customData[p + 2] = chVResult;
                    AteMeasure[p] = chResult;
                    TempValue[p] = chTemp;
                    //ForceCurrent += CurrentStep;
                    ForceV += Vstep;
                }
                PPMU.Force(PmuPinName, 0, PpmuMode.FVMI, PpmuIRange._2mA, VRange.Normal);

                WriteSingleFile(sw: sw,
                                slot: SlotNum,
                                dna: arm_dna,
                                type: "PMU",
                                channel: ch,
                                mode: "FVMI",
                                rload: "Hi-Z",
                                extR: ExtBoard_Res,
                                range: "2mA",
                                ForceValue: ForceValue,
                                AteMeasure: AteMeasure,
                                DmmMeasure: DMMValue,
                                TempValue: TempValue,
                                contextFormat: "RintGND");

                sw.Flush();
                sw.Close();

                Metadata_handler(swdata: swdata,
                                 SlotNum: SlotNum,
                                 slotList: slotList,
                                 arm_dna: arm_dna,
                                 context: context,
                                 init_Flag: false,
                                 Type: "PMU",
                                 Channel: ch,
                                 Mode: "FVMI",
                                 Rload: "Hi-Z",
                                 Range: "2mA",
                                 filepath: filepath,
                                 filetime: filetime);

            }
            swdata.Flush();
            swdata.Close();
            Thread.Sleep(100);

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL");
        }

        void Rint_FVMI_Test(IFlowRunnerContext context, TestVersion testVersion)
        {
            #region Init Config & Variables
            List<int> ChannelDps = new List<int>();
            List<int> ChannelPmu = new List<int>();
            //-----Select PreTest or ReTest-----
            for (int m = 0; m < PmuChannelCount; m++)
            {
                ChannelPmu.Add(m + 1);
            }
            //-----get all connect slot number-----
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            //-----config Board-----
            byte[] armDnaPortCmd = new byte[2] { 14, 57 };
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd);
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;
            Dictionary<int, int> M013_PMU = new Dictionary<int, int>()
            {
                {166,178 },
                {167,177 },
                {168,176 },
                {169,175 },
                {230,242 },
                {231,241 },
                {232,240 },
                {233,239 }
            };
            //---------Thread Locker--------
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: true);

            //-----Move File To History-----
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Single");

           
            //-----Start Write MetaData-----
            StreamWriter swdata;
            swdata = new StreamWriter(METADATA_PATH, true, Encoding.UTF8)
            {
                AutoFlush = true
            };

            Metadata_handler(
            swdata: swdata,
            SlotNum: SlotNum,
            slotList: slotList,
            arm_dna: arm_dna,
            context: context,
            init_Flag: true
            );
            #endregion

            #region Config DMM
            //-----config dmm3458A and ExtCalibrationBoard----- 
            KeysightDMM3458A dmm = new KeysightDMM3458A();
            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string extConnStr = Select_IP[testVersion];
            int extPort = port;

            dmm.InitDMM(ksightConnStr);
            #endregion

            //-----Read R File-----                
            double[,] ExtBoard_Res = ReadRext(EXT_CAL_INIT_PATH + "ExtBoardRes.csv");

            extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, 1, ExternalCalibrationMode.Channel, 1, ExtCaliVI.V, ExtCaliLoad.RC_RL7, 0);   //1kΩ
            double rload = GetRloadValue(dmm, 2000, 5);
            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");


            #region The Test 

            for (int loopk = 0; loopk < PmuChannelCount; loopk++)
            {
                int ch = ChannelPmu[loopk];
                int ch1 = ChannelPmu[loopk];
                if (ChannelPmu[loopk] >= 1 && ChannelPmu[loopk] <= 18)
                {
                    ch1 = ChannelPmu[loopk] + 46;
                }
                else if (ChannelPmu[loopk] >= 19 && ChannelPmu[loopk] <= 23)
                {
                    ch1 = ChannelPmu[loopk] + 110;
                }
                else if (ChannelPmu[loopk] >= 24 && ChannelPmu[loopk] <= 46)
                {
                    ch1 = ChannelPmu[loopk];
                }
                else if (ChannelPmu[loopk] >= 47 && ChannelPmu[loopk] <= 64)
                {
                    ch1 = ChannelPmu[loopk] - 46;
                }
                else if (ChannelPmu[loopk] >= 65 && ChannelPmu[loopk] <= 82)
                {
                    ch1 = ChannelPmu[loopk] + 46;
                }
                else if (ChannelPmu[loopk] >= 83 && ChannelPmu[loopk] <= 87)
                {
                    ch1 = ChannelPmu[loopk] + 110;
                }
                else if (ChannelPmu[loopk] >= 88 && ChannelPmu[loopk] <= 110)
                {
                    ch1 = ChannelPmu[loopk];
                }
                else if (ChannelPmu[loopk] >= 111 && ChannelPmu[loopk] <= 113)
                {
                    ch1 = ChannelPmu[loopk] - 46;
                }
                else if (ChannelPmu[loopk] >= 114 && ChannelPmu[loopk] <= 128)
                {
                    ch1 = ChannelPmu[loopk] - 46;
                }
                else if (ChannelPmu[loopk] >= 129 && ChannelPmu[loopk] <= 133)
                {
                    ch1 = ChannelPmu[loopk] - 110;
                }
                else if (ChannelPmu[loopk] >= 134 && ChannelPmu[loopk] <= 147)
                {
                    ch1 = ChannelPmu[loopk] + 45;
                }
                else if (ChannelPmu[loopk] >= 148 && ChannelPmu[loopk] <= 165)
                {
                    ch1 = ChannelPmu[loopk] + 9;
                }
                else if (ChannelPmu[loopk] >= 166 && ChannelPmu[loopk] <= 169)
                {
                    ch1 = M013_PMU[ChannelPmu[loopk]];
                }
                else if (ChannelPmu[loopk] >= 170 && ChannelPmu[loopk] <= 172)
                {
                    ch1 = ChannelPmu[loopk] - 36;
                }
                else if (ChannelPmu[loopk] >= 173 && ChannelPmu[loopk] <= 192)
                {
                    ch1 = ChannelPmu[loopk] - 36;
                }
                else if (ChannelPmu[loopk] >= 193 && ChannelPmu[loopk] <= 197)
                {
                    ch1 = ChannelPmu[loopk] - 110;
                }
                else if (ChannelPmu[loopk] >= 198 && ChannelPmu[loopk] <= 211)
                {
                    ch1 = ChannelPmu[loopk] + 45;
                }
                else if (ChannelPmu[loopk] >= 212 && ChannelPmu[loopk] <= 229)
                {
                    ch1 = ChannelPmu[loopk] + 9;
                }
                else if (ChannelPmu[loopk] >= 230 && ChannelPmu[loopk] <= 233)
                {
                    ch1 = M013_PMU[ChannelPmu[loopk]];
                }
                else if (ChannelPmu[loopk] >= 234 && ChannelPmu[loopk] <= 256)
                {
                    ch1 = ChannelPmu[loopk] - 36;
                }

                #region Test Config
                double ForceVoltage = -2;
                double VoltageStep = 1;
                string[] PmuPinName = { ("A" + (ChannelPmu[loopk] < 10 ? "0" : "") + ChannelPmu[loopk]) };
                // int ch = ChannelPmu[loopk];
                double[] AteMeasure = new double[SampliCount];
                double[] ForceValue = new double[SampliCount];
                double[] DMMValue = new double[SampliCount];
                double[] TempValue = new double[SampliCount];

                RELAY.SwitchMode(RelayMode.Open);
                RELAY.SwitchToPPMU(PmuPinName);
                string filepath = "Slot" + SlotNum + "_PMU_" + "ch" + ChannelPmu[loopk] + "_" + "FVMV" + "_" + "Hi-Z" + "_" + "2mA" + ".csv";
                string filename = EXT_CAL_PATH + filepath;
                #endregion

                extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch1, ExtCaliVI.V, ExtCaliLoad.RC_RL7, 0);//change channel
                if (loopk == 0)
                {
                    DelayHelper.Sleep(20);
                }

                #region Actual Test
                for (int p = 0; p < SampliCount; p++)
                {
                    PPMU.Force(PmuPinName, ForceVoltage, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);

                    Thread.Sleep(20);
                    List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMV"), 128, 100);
                    double chResult = GetATEChannelMeasure(siList, PmuPinName);

                    double dmmRead = dmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.VOLT, 1, 7.5);

                    double[] readTemp = PPMU.ReadTemperature();
                    double chTemp = readTemp[GetPMUTempSensorIndex(ch)];

                    ForceValue[p] = ForceVoltage;
                    AteMeasure[p] = chResult;
                    DMMValue[p] = dmmRead;
                    TempValue[p] = chTemp;
                    ForceVoltage += VoltageStep;
                }
                #endregion

                PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);

                #region File Writing
                StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                {
                    AutoFlush = true
                };
                WriteSingleFile(sw: sw,
                                slot: SlotNum,
                                dna: arm_dna,
                                type: "PMU",
                                channel: ch,
                                mode: "FVMV",
                                rload: rload.ToString(),
                                extR: ExtBoard_Res,
                                range: "2mA",
                                ForceValue: ForceValue,
                                AteMeasure: AteMeasure,
                                DmmMeasure: DMMValue,
                                TempValue: TempValue);

                sw.Flush();
                sw.Close();

                Metadata_handler(swdata: swdata,
                                 SlotNum: SlotNum,
                                 slotList: slotList,
                                 arm_dna: arm_dna,
                                 context: context,
                                 init_Flag: false,
                                 Type: "PMU",
                                 Channel: ch,
                                 Mode: "FVMV",
                                 Rload: rload.ToString(),
                                 Range: "2mA",
                                 filepath: filepath,
                                 filetime: filetime);
                #endregion
            }

            #endregion


            swdata.Flush();
            swdata.Close();
            Thread.Sleep(1000);

            #region Post Process
            #region File Process
            StreamReader metareader = new StreamReader(METADATA_PATH, Encoding.UTF8);
            List<string> dnaip = new List<string>();
            List<string> path = new List<string>();
            List<string> datassingle = new List<string>();
            int cnnt = 0;
            while (!metareader.EndOfStream)
            {
                string str = metareader.ReadLine();
                if (cnnt > 6)
                {
                    if (str.Split(',')[0] == arm_dna)
                    {
                        path.Add(str);
                    }
                }
                cnnt = cnnt + 1;
            }
            metareader.Close();

            string pmurapth = EXT_CAL_PATH + context.Communicator.ServerIP + "_" + "Pmur" + ".txt";
            StreamWriter Pmur = new StreamWriter(pmurapth, true);
            Pmur.AutoFlush = true;
            #endregion
            #region Rint Calculation
            for (int p = 0; p < path.Count; p++)
            {
                string dna = path[p].Split(',')[0];
                string file = path[p].Split(',')[8];
                StreamReader singlefile = new StreamReader(EXT_CAL_PATH + file, Encoding.UTF8);
                while (!singlefile.EndOfStream)
                {
                    datassingle.Add(singlefile.ReadLine());
                }
                double RL = Convert.ToDouble(datassingle[6].Split(',')[1]);//150
                double rext = Convert.ToDouble(datassingle[8].Split(',')[1]);
                int ChannelNum = Convert.ToInt32(datassingle[4].Split(',')[1]);
                double res = 0;
                for (int linefile = 14; linefile < 19; linefile++)
                {
                    if (linefile == 16)
                    {
                        continue;
                    }
                    double ateV = Convert.ToDouble(datassingle[linefile].Split(',')[1]);
                    double voltage = Convert.ToDouble(datassingle[linefile].Split(',')[2]);
                    double iii = voltage / RL;                                  //???
                    double diff = ateV - voltage;
                    double rrr = diff / iii;                                    //???
                    res = res + (rrr - rext);                                   //Rint?
                }
                res = res / 4;                                                  //Average
                string ChannelFormat;
                if (ChannelNum < 10)
                {
                    ChannelFormat = "00" + Convert.ToString(ChannelNum);
                }
                else if ((ChannelNum >= 10) && (ChannelNum < 100))
                {
                    ChannelFormat = "0" + Convert.ToString(ChannelNum);
                }
                else
                {
                    ChannelFormat = Convert.ToString(ChannelNum);
                }
                Pmur.WriteLine($"ch {ChannelFormat} : {res:F3}");
                rInt[ChannelNum - 1] = res;                     //Put R_Int into array
                datassingle.Clear();
                singlefile.Close();
            }
            #endregion
            Pmur.Close();
            #endregion

            #region Thread Lock
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: false);
            #endregion
        }


        /// <summary>
        /// Verify if the ExtCalibration Board is working as it should.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="testVersion"></param>
        void ExtBoard_Verify(IFlowRunnerContext context,TestVersion testVersion,double diff_Limit)
        {
            #region Init Config & Variables
            List<int> ChannelDps = new List<int>();
            List<int> ChannelPmu = new List<int>();
            //-----Select PreTest or ReTest-----
            for (int m = 0; m < 256; m++)
            {
                ChannelPmu.Add(m + 1);
            }
            //-----get all connect slot number-----
            var slotInfos = context.FlowCatalog.GetAll<SlotInfo>();
            List<int> slotList = new List<int>();
            for (int slotLen = 0; slotLen < slotInfos.Count; slotLen++)
            {
                if (slotInfos[slotLen].FirmwareVersion == "")
                {
                    continue;
                }
                slotList.Add(slotInfos[slotLen].No);
            }
            //-----config Board-----
            byte[] armDnaPortCmd = new byte[2] { 14, 57 };
            byte[] armDnaRaw = context.Communicator.Send(armDnaPortCmd);
            armDnaRaw = armDnaRaw.Reverse().ToArray();
            string arm_dna = BitConverter.ToUInt64(armDnaRaw, 0).ToString();
            int SlotNum = context.Communicator.SlotNo;

            //---------Thread Locker--------
            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL", lockFlag: true);

            //-----Move File To History-----
            File_Mover(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL_Single");  

            //-----Start Write MetaData-----
            StreamWriter swdata;
            swdata = new StreamWriter(METADATA_PATH, true, Encoding.UTF8)
            {
                AutoFlush = true
            };

            Metadata_handler(
            swdata: swdata,
            SlotNum: SlotNum,
            slotList: slotList,
            arm_dna: arm_dna,
            context: context,
            init_Flag: true
            );
            #endregion

            #region Config DMM
            //-----config dmm3458A and ExtCalibrationBoard----- 
            KeysightDMM3458A dmm = new KeysightDMM3458A();

            ExternalCalibrationHandle extCaliHandle = new ExternalCalibrationHandle();
            string extConnStr = Select_IP[testVersion];
            int extPort = port;

            dmm.InitDMM(ksightConnStr);
            #endregion
            //-----Read R File-----                
            double[,] ExtBoard_Res = ReadRext(EXT_CAL_INIT_PATH + "ExtBoardRes.csv");
            string filetime = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");

            #region The Test 
            extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, 1, ExternalCalibrationMode.Channel, 1, ExtCaliVI.I, ExtCaliLoad.RC_RL18, 0);
            double rload = GetRloadValue(dmm, 2000, 5);
            if (rload > 1)
            {
                throw new Exception("rload larger than 1");
            }
            for (int loopk = 0; loopk < 256; loopk++)
            {
                int ch = ChannelPmu[loopk];
                #region Test Config
                string[] PmuPinName = { ("A" + (ChannelPmu[loopk] < 10 ? "0" : "") + ChannelPmu[loopk]) };
                RELAY.SwitchMode(RelayMode.Open);
                RELAY.SwitchToPPMU(PmuPinName);
                double ForceVoltage = -0.015;
                double VoltageStep = 0.0075;
                string filepath = "Slot" + SlotNum + "_PMU_" + "ch" + ChannelPmu[loopk] + "_" + "FVMI" + "_" + "Hi-Z" + "_" + "2mA" + ".csv";
                string filename = EXT_CAL_PATH + filepath;
                //  int ch = ChannelPmu[loopk];

                double[] AteMeasure = new double[SampliCount];
                double[] ForceValue = new double[SampliCount];
                double[] DMMValue = new double[SampliCount];
                double[] TempValue = new double[SampliCount];
                #endregion

                extCaliHandle.SetPpmuExternalCalibration(extConnStr, extPort, SlotNum, ExternalCalibrationMode.Channel, ch, ExtCaliVI.I, ExtCaliLoad.RC_RL18, 0);//change channel
                
                if (loopk == 0)
                {
                    DelayHelper.Sleep(20);
                }
                #region Actual Test
                for (int p = 0; p < SampliCount; p++)
                {
                    PPMU.Force(PmuPinName, ForceVoltage, PpmuMode.FVMI, PpmuIRange._2mA, VRange.Normal);

                    Thread.Sleep(20);
                    List<SiteInfo> siList = PPMU.Measure(PmuPinName, true, context.BinHandler.GetBinningByTestSuite("ExtCalibration_FVMI"), 128, 100);
                    double chResult = GetATEChannelMeasure(siList, PmuPinName);

                    double dmmRead = dmm.GetDmmMeasureData(KeysightDMM3458A.KeysightMeasMode.CURR, 1, 1);

                    double[] readTemp = PPMU.ReadTemperature();
                    double chTemp = readTemp[GetPMUTempSensorIndex(ch)];

                    ForceValue[p] = ForceVoltage;
                    AteMeasure[p] = chResult;
                    DMMValue[p] = dmmRead;
                    TempValue[p] = chTemp;
                    ForceVoltage += VoltageStep;
                }
                #endregion

                PPMU.Force(PmuPinName, 0, PpmuMode.FVMV, PpmuIRange._2mA, VRange.Normal);
                #region File Writing
                StreamWriter sw = new StreamWriter(filename, true, Encoding.UTF8)
                {
                    AutoFlush = true
                };
                WriteSingleFile(sw: sw,
                                slot: SlotNum,
                                dna: arm_dna,
                                type: "PMU",
                                channel: ch,
                                mode: "FVMV",
                                rload: "Hi-Z",
                                extR: ExtBoard_Res,
                                range: "2mA",
                                ForceValue: ForceValue,
                                AteMeasure: AteMeasure,
                                DmmMeasure: DMMValue,
                                TempValue: TempValue);

                sw.Flush();
                sw.Close();

                Metadata_handler(swdata: swdata,
                                 SlotNum: SlotNum,
                                 slotList: slotList,
                                 arm_dna: arm_dna,
                                 context: context,
                                 init_Flag: false,
                                 Type: "PMU",
                                 Channel: ch,
                                 Mode: "FVMI",
                                 Rload: "Hi-Z",
                                 Range: "2mA",
                                 filepath: filepath,
                                 filetime: filetime);

                #endregion
            }
            #endregion
            swdata.Flush();
            swdata.Close();

            #region Post Process
            #region File Process
            StreamReader metareader = new StreamReader(METADATA_PATH, Encoding.UTF8);
            List<string> dnaip = new List<string>();
            List<string> path = new List<string>();
            List<string> datassingle = new List<string>();
            int cnnt = 0;
            while (!metareader.EndOfStream)
            {
                string str = metareader.ReadLine();
                if (cnnt > 6)
                {
                    if (str.Split(',')[0] == arm_dna)
                    {
                        path.Add(str);
                    }
                }
                cnnt = cnnt + 1;
            }
            metareader.Close();

            string pmurapth = EXT_CAL_PATH + context.Communicator.ServerIP + "_" + "Pmur" + ".txt";
            StreamWriter Pmur = new StreamWriter(pmurapth, true);
            Pmur.AutoFlush = true;
            #endregion
            #region Rint Calculation
            for (int p = 0; p < path.Count; p++)
            {
                string dna = path[p].Split(',')[0];
                string file = path[p].Split(',')[8];
                StreamReader singlefile = new StreamReader(EXT_CAL_PATH + file, Encoding.UTF8);
                while (!singlefile.EndOfStream)
                {
                    datassingle.Add(singlefile.ReadLine());
                }
                
                int ChannelNum = Convert.ToInt32(datassingle[4].Split(',')[1]);
                double res = 0;
                double sum = 0;
                for (int linefile = 14; linefile < 19; linefile++)
                {
                    if (linefile == 16)
                    {
                        continue;
                    }
                    double forceV = Convert.ToDouble(datassingle[linefile].Split(',')[0]);
                    double voltage = Convert.ToDouble(datassingle[linefile].Split(',')[2]); 
                    res = forceV / voltage;
                    sum += res;

                }
                res = sum / 4;                                                  //Average
                rInt[ChannelNum - 1] = res;                     //Put R_Int into array
                datassingle.Clear();
                singlefile.Close();
            }
            double diff = 0;
            for (int i = 0; i < path.Count - 1; i++)
            {
                if (Math.Abs(rInt[i] - rInt[i + 1]) > diff)                         //Check R Diff
                {
                    diff = Math.Abs(rInt[i] - rInt[i + 1]);
                }
                if (diff > diff_Limit)
                {
                    Pmur.WriteLine($"Failed! At Channel {i + 1}, Diff={diff}");
                    break;
                }
                if (diff == 0 || Math.Abs(rInt[i])>50)                              //Same Value OR Unreasonable Value
                {
                    Pmur.WriteLine($"Failed! At Channel {i + 1}, Diff={diff}");
                    break;
                }
            }
            if (Math.Abs(rInt[path.Count - 1])>50)                                  //We shall check the last Channel
            {
                Pmur.WriteLine($"Failed! At Channel {path.Count}, Diff={diff}");
            }
            else if (diff < diff_Limit)                     
            {
                Pmur.WriteLine($"Passed! Max Diff={diff}");
            }
            for (global::System.Int32 i = 0; i < path.Count; i++)
            {
                string ChannelFormat;
                if (i < 9)
                {
                    ChannelFormat = "00" + Convert.ToString(i+1);
                }
                else if ((i >= 9) && (i < 99))
                {
                    ChannelFormat = "0" + Convert.ToString(i+1);
                }
                else
                {
                    ChannelFormat = Convert.ToString(i+1);
                }
                Pmur.WriteLine($"ch {ChannelFormat} : {rInt[i]:F3}");
            }
           

            #endregion
            Pmur.Close();
            #endregion

            SlotThreadLocker(SlotNum: SlotNum, slotList: slotList, pathFlag: "CAL");
            
        }


        #endregion

        [TestrongTestCase]
        public void Reset(IFlowRunnerContext context)
        {
            ExternalCalibrationReset(context);
        }

        [TestrongTestCase]
        public void DmmGetRes(IFlowRunnerContext context)
        {
            DmmGetResValue(context, SelectTestVersion);
        }

        [TestrongTestCase]
        public void Ext_Calibration_Pre(IFlowRunnerContext context)
        {
            ExternalCalibrationCollect(context, SelectTestVersion, true, true);
        }
        [TestrongTestCase]
        public void Write_CalFiles(IFlowRunnerContext context)
        {
            ExternalCalibrationWriteCalFiles(context);
        }

        [TestrongTestCase]
        public void Ext_Calibration_Post(IFlowRunnerContext context)
        {
            ExternalCalibrationCollect(context, SelectTestVersion, true, false);
        }
        [TestrongTestCase]
        public void RintReset(IFlowRunnerContext context)
        { 
            Rint_Reset(context);
        }
        [TestrongTestCase]
        public void Rint_Pre(IFlowRunnerContext context)
        {
            Rint_FVMV_2mA_Pre(context, SelectTestVersion);
        }
        [TestrongTestCase]
        public void RintDataUpload(IFlowRunnerContext context)
        {
            Rint_DataUpload(context);
        }
        [TestrongTestCase]
        public void Check_ExtBoard(IFlowRunnerContext context)
        {
            ExtBoard_Verify(context, SelectTestVersion, 5);
        }

        [TestrongTestCase]
        public void Rint_test(IFlowRunnerContext context)
        {
            Rint_FVMI_Test(context, SelectTestVersion);
        }
        [TestrongTestCase]
        public void Rint_Post(IFlowRunnerContext context)
        {
            Rint_FVMV_2mA_Post(context, SelectTestVersion); 
        }
        [TestrongTestCase]
        public void Rint_Test(IFlowRunnerContext context)
        {
            Rint_Test(context, SelectTestVersion); 
        }
        [TestrongTestCase]
        public void PmurUpload(IFlowRunnerContext context)
        {
            Pmur_Upload(context);
        }
        [TestrongTestCase]
        public void ReTest(IFlowRunnerContext context)
        {
            ExternalCalibrationCollect(context, SelectTestVersion, false, false);   
        }

        [TestrongTestCase]
        public void Freq_Test(IFlowRunnerContext context)
        {
            ExternalCalibrationFreqCollect(context, SelectTestVersion);
        }
        [TestrongTestCase]
        public void Rint_FVMI_Gnd(IFlowRunnerContext context)
        {
            Rint_GND_FVMI_2mA(context);
        }
    }
}
