using System;
using System.Collections;
using System.Data;
using System.Linq;
using AR;

namespace Project
{
    public class PindefineI
    {
        public int idx { get; set; }
        public string description { get; set; }
        public int terminalno { get; set; }
        public string Title { get; set; }
        public bool Invert { get; set; }
        public PindefineI(eDIName pin)
        {
            idx = (int)pin;
            Title = pin.ToString();
            terminalno = (int)pin;
            Invert = false;
        }
        public string name { get { return $"X{idx:X2}"; } }
    }
    public class PindefineO
    {
        public int idx { get; set; }
        public string description { get; set; }
        public int terminalno { get; set; }
        public string Title { get; set; }
        public PindefineO(eDOName pin)
        {
            idx = (int)pin;
            Title = pin.ToString();
            terminalno = (int)pin;
        }
        public string name { get { return $"Y{idx:X2}"; } }
    }
    public class PinList
    {
        public PindefineI[] input { get; set; }
        public PindefineO[] output { get; set; }

        /// <summary>
        /// 입력포트 목록을 반환합니다.
        /// 실제 터미널 번호에 매칭되는 이름으로 반환합니다.
        /// </summary>
        public string[] GetDIName
        {
            get
            {
                return input.OrderBy(t => t.terminalno).ToList().Select(t => t.Title).ToArray();
            }
        }

        public string[] GetDIPinName
        {
            get
            {
                return input.OrderBy(t => t.idx).ToList().Select(t => t.name).ToArray();
            }
        }

        /// <summary>
        /// 입력포트 목록을 반환합니다.
        /// 실제 터미널 번호에 매칭되는 이름으로 반환합니다.
        /// </summary>
        public string[] GetDOName
        {
            get
            {
                return output.OrderBy(t => t.terminalno).ToList().Select(t => t.Title).ToArray();
            }
        }
        public string[] GetDOPinName
        {
            get
            {
                return output.OrderBy(t => t.idx).ToList().Select(t => t.name).ToArray();
            }
        }
        public PindefineI this[eDIName pin]
        {
            get
            {
                return input[(int)pin];
            }
        }
        public PindefineO this[eDOName pin]
        {
            get
            {
                return output[(int)pin];
            }
        }
        public Boolean SetInputData(DataSet1.InputDescriptionDataTable dt)
        {
            bool retval = true;
            var names = Enum.GetNames(typeof(eDIPin));
            if (this.input == null)   //초기데이터생성
            {
                this.input = new PindefineI[names.Length];
                for (int i = 0; i < input.Length; i++)
                    input[i] = new PindefineI((eDIName)i);
            }

            if (dt.Any())
            {
                foreach (DataSet1.InputDescriptionRow dr in dt)
                {
                    if (dr.RowState == DataRowState.Detached || dr.RowState == DataRowState.Detached) continue;
                    var item = this.input[dr.Idx];
                    if (dr.IsDescriptionNull() == false) item.description = dr.Description;
                    if (dr.IsTerminalNoNull() == false && dr.TerminalNo >= 0) item.terminalno = dr.TerminalNo;
                }
            }
            return retval;

        }

        public Boolean SetOutputData(DataSet1.OutputDescriptionDataTable dt)
        {
            bool retval = true;
            var names = Enum.GetNames(typeof(eDOPin));
            if (this.output == null) //초기데이터새엇ㅇ
            {
                this.output = new PindefineO[names.Length];
                for (int i = 0; i < output.Length; i++)
                    output[i] = new PindefineO((eDOName)i);
            }
            if (dt.Any())
            {
                foreach (DataSet1.OutputDescriptionRow dr in dt)
                {
                    if (dr.RowState == DataRowState.Detached || dr.RowState == DataRowState.Detached) continue;
                    var item = this.output[dr.Idx];
                    if (dr.IsDescriptionNull() == false) item.description = dr.Description;
                    if (dr.IsTerminalNoNull() == false && dr.TerminalNo >= 0) item.terminalno = dr.TerminalNo;
                }
            }
            return retval;
        }

        public bool CheckData()
        {
            return false;
        }
    }


    public static partial class DIO
    {        
        public static PinList Pin { get; set; }
        static int GetPinTerminal(eDIName pin)
        {
            var pindef = Pin[pin];
            return pindef.terminalno;
        }
        static int GetPinTerminal(eDOName pin)
        {
            var pindef = Pin[pin];
            return pindef.terminalno;
        }

        public static void InitDIOSensitive()
        {
            //인식 딜레이를 건다
            PUB.dio.SetInputSensitivity(0, 0);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.PORTL_DET_UP), AR.SETTING.Data.PortDetectFall, AR.SETTING.Data.PortDetectRise);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.PORTC_DET_UP), AR.SETTING.Data.PortDetectFall, AR.SETTING.Data.PortDetectRise);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.PORTR_DET_UP), AR.SETTING.Data.PortDetectFall, AR.SETTING.Data.PortDetectRise);
                                        
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.BUT_AIRF), AR.SETTING.Data.AirChange, AR.SETTING.Data.AirChange);
                                        
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.DOORF1), AR.SETTING.Data.SaftyDetectFall, AR.SETTING.Data.SaftyDetectRise);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.DOORF2), AR.SETTING.Data.SaftyDetectFall, AR.SETTING.Data.SaftyDetectRise);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.DOORF3), AR.SETTING.Data.SaftyDetectFall, AR.SETTING.Data.SaftyDetectRise);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.DOORR1), AR.SETTING.Data.SaftyDetectFall, AR.SETTING.Data.SaftyDetectRise);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.DOORR2), AR.SETTING.Data.SaftyDetectFall, AR.SETTING.Data.SaftyDetectRise);
            PUB.dio.SetInputSensitivity(GetPinTerminal(eDIName.DOORR3), AR.SETTING.Data.SaftyDetectFall, AR.SETTING.Data.SaftyDetectRise);

            PUB.log.AddAT("DIO Sensor Sensitivity Setting");
        }



        /// <summary>
        /// 지정한 출력핀의 상태를 변경하고 최대 10초간 상태를 모니터링 합니다.
        /// </summary>
        /// <param name="doPin"></param>
        /// <param name="isFirst"></param>
        /// <param name="stepTime"></param>
        /// <param name="checkValue"></param>
        /// <param name="sendIntervalMs"></param>
        /// <param name="timeoutSec"></param>
        /// <returns></returns>
        public static eNormalResult checkDigitalO(eDOName doPin, TimeSpan stepTime, Boolean checkValue, int sendIntervalMs = 1000, int timeoutSec = 0, bool raiseerror = true)
        {

            //eIOCheckResult result = eIOCheckResult.Complete;
            eNormalResult retval = eNormalResult.False;
            if (timeoutSec == 0) timeoutSec = AR.SETTING.Data.Timeout_DIOCommand;


            //지정한 출력핀이 조건에 맞지 않을 경우ㅍ
            var curValue = DIO.GetIOOutput(doPin);
            if (curValue != checkValue)
            {
                //Offt신호는 1초에 1번씩 전송하게 한다.
                var ts = DateTime.Now - PUB.Result.doCheckTime[(int)doPin];
                if (ts.TotalMilliseconds >= sendIntervalMs)
                {
                    SetOutput(doPin, checkValue);
                    PUB.Result.doCheckTime[(int)doPin] = DateTime.Now;
                }

                //전체 시간이 10초를 넘어가면 오류로 처리함
                if (stepTime.TotalSeconds >= timeoutSec)
                {
                    if (raiseerror)
                        PUB.Result.SetResultTimeOutMessage(doPin, checkValue, eNextStep.PAUSE);

                    retval = eNormalResult.Error;
                }
            }
            else retval = eNormalResult.True;
            return retval;
        }

        public static eNormalResult checkDigitalO(eDIName doPin, TimeSpan stepTime, Boolean checkValue, int timeoutSec = 0, bool raiseerror = true, eECode timeoutcode = eECode.NOTSET
            )
        {
            //eIOCheckResult result = eIOCheckResult.Complete;
            var retval = eNormalResult.False;
            if (timeoutSec == 0) timeoutSec = (int)AR.SETTING.Data.Timeout_DIOCommand;

            //지정한 출력핀이 조건에 맞지 않을 경우ㅍ
            var curValue = DIO.GetIOInput(doPin);
            if (curValue != checkValue)
            {
                //전체 시간이 10초를 넘어가면 오류로 처리함
                //var diRunTime = DateTime.Now - Pub.Result.diCheckTime[shutIdx, (int)doPin];
                if (stepTime.TotalSeconds >= timeoutSec)
                {
                    if (raiseerror)
                    {
                        if (timeoutcode == eECode.NOTSET)
                            PUB.Result.SetResultTimeOutMessage(doPin, checkValue, eNextStep.PAUSE);
                        else
                            PUB.Result.SetResultMessage(eResult.SENSOR, timeoutcode, eNextStep.PAUSE, doPin);
                    }
                    retval = eNormalResult.Error;
                }
            }
            else retval = eNormalResult.True;
            return retval;
        }


        public static Boolean IsEmergencyOn()
        {
            //둘중 하나라도 켜져있드면 비상 상태이다
            var b1 = GetIOInput(eDIName.BUT_EMGF);
            return b1;
        }

        /// <summary>
        /// 감지센서확인
        /// </summary>
        /// <returns></returns>
        public static int isVacOKL()
        {
            var cnt = 0;
            if (GetIOOutput(eDOName.PICK_VAC1)) cnt += 1;
            if (GetIOOutput(eDOName.PICK_VAC2)) cnt += 1;
            if (GetIOOutput(eDOName.PICK_VAC3)) cnt += 1;
            if (GetIOOutput(eDOName.PICK_VAC4)) cnt += 1;
            return cnt;
        }

        /// <summary>
        /// 포트에 장작된 카트의 크기를 반환합니다. 없는경우 0, 7,13 입니다.
        /// </summary>
        /// <param name="idx">Port Index(left=0, Center=1, Right=2)</param>
        /// <returns></returns>
        public static eCartSize getCartSize(int idx)
        {
            var s07 = false;
            var s13 = false;


            //컨베어모드에서는 무조건 중앙크기와 동일하게 한다 (오류나지않게)
            if (VAR.BOOL[eVarBool.Use_Conveyor])
            {
                s07 = DIO.GetIOInput(eDIName.PORT1_SIZE_07);
                s13 = DIO.GetIOInput(eDIName.PORT1_SIZE_13);
            }
            else
            {
                if (idx == 0)
                {

                    s07 = DIO.GetIOInput(eDIName.PORT0_SIZE_07);
                    s13 = DIO.GetIOInput(eDIName.PORT0_SIZE_13);
                }
                else if (idx == 1)
                {
                    s07 = DIO.GetIOInput(eDIName.PORT1_SIZE_07);
                    s13 = DIO.GetIOInput(eDIName.PORT1_SIZE_13);
                }
                else
                {
                    s07 = DIO.GetIOInput(eDIName.PORT2_SIZE_07);
                    s13 = DIO.GetIOInput(eDIName.PORT2_SIZE_13);
                }
            }


            if (s07 == false && s13 == false) return eCartSize.None;
            else if (s13 == true) return eCartSize.Inch13;
            else return eCartSize.Inch7;
        }

       
        /// <summary>
        /// * 입력값을 확인합니다
        /// </summary>
        /// <param name="pin"></param>
        /// <returns></returns>
        public static Boolean GetIOInput(eDIName pin)
        {
            var pindef = Pin[pin];
            var curValue = PUB.dio.GetDIValue(pindef.terminalno);

            //B접점으로 쓸 것들만 반전 시킨다.
            if (pindef.Invert)
            {
                curValue = !curValue;
            }
            else if (pin == eDIName.BUT_EMGF)
            {
                if (SETTING.System.ReverseSIG_Emgergency) curValue = !curValue;
            }
            else if (pin == eDIName.PICKER_SAFE)
            {
                if (SETTING.System.ReverseSIG_PickerSafe) curValue = !curValue;
            }
            else if (pin == eDIName.BUT_AIRF)
            {
                if (SETTING.System.ReverseSIG_ButtonAir) curValue = !curValue;
            }
            else if (pin == eDIName.DOORF1 || pin == eDIName.DOORF2 || pin == eDIName.DOORF3)
            {
                if (SETTING.System.ReverseSIG_DoorF) curValue = !curValue;
            }
            else if (pin == eDIName.DOORR1 || pin == eDIName.DOORR2 || pin == eDIName.DOORR3)
            {
                if (SETTING.System.ReverseSIG_DoorR) curValue = !curValue;
            }
            else if (pin == eDIName.AIR_DETECT)
            {
                if (SETTING.System.ReverseSIG_AirCheck) curValue = !curValue;
            }
            else if (pin == eDIName.PORTL_LIM_UP || pin == eDIName.PORTC_LIM_UP || pin == eDIName.PORTR_LIM_UP)
            {
                if (SETTING.System.ReverseSIG_PortLimitUp) curValue = !curValue;
            }
            else if (pin == eDIName.PORTL_LIM_DN || pin == eDIName.PORTC_LIM_DN || pin == eDIName.PORTR_LIM_DN)
            {
                if (SETTING.System.ReverseSIG_PortLimitDn) curValue = !curValue;
            }
            else if (pin == eDIName.PORTL_DET_UP)
            {
                if (SETTING.System.ReverseSIG_PortDetect0Up) curValue = !curValue;
            }
            else if (pin == eDIName.PORTC_DET_UP)
            {
                if (SETTING.System.ReverseSIG_PortDetect1Up) curValue = !curValue;
            }
            else if (pin == eDIName.PORTR_DET_UP)
            {
                if (SETTING.System.ReverseSIG_PortDetect2Up) curValue = !curValue;
            }
            else if (pin == eDIName.L_CONV1 || pin == eDIName.L_CONV4)
                curValue = !curValue;
            else if (pin == eDIName.R_CONV1 || pin == eDIName.R_CONV4)
                curValue = !curValue;
            return curValue;
        }

        /// <summary>
        /// * 출력값을 확인합니다.
        /// </summary>
        /// <param name="pin"></param>
        /// <returns></returns>
        public static Boolean GetIOOutput(eDOName pin)
        {
            var pindef = Pin[pin];
            return PUB.dio.GetDOValue(pindef.terminalno);
        }

        /// <summary>
        /// 포트내의 안전센서 여부
        /// </summary>
        /// <returns></returns>
        public static Boolean isSaftyDoorF(Boolean RealSensor = false)
        {
            //모든 포트가 안전해야 전체가 안전한것이다
            return isSaftyDoorF(0, RealSensor) && isSaftyDoorF(1, RealSensor) && isSaftyDoorF(2, RealSensor);
        }
        public static Boolean isSaftyDoorR(Boolean RealSensor = false)
        {
            //모든 포트가 안전해야 전체가 안전한것이다
            return isSaftyDoorR(0, RealSensor) && isSaftyDoorR(1, RealSensor) && isSaftyDoorR(2, RealSensor);
        }


        public static Boolean isSaftyDoorF(int idx, Boolean RealSensor)
        {
            //비활성화한경우 참 반환
            if (RealSensor)
            {
                if (idx == 0) return DIO.GetIOInput(eDIName.DOORF1) == false;
                else if (idx == 1) return DIO.GetIOInput(eDIName.DOORF2) == false;
                else if (idx == 2) return DIO.GetIOInput(eDIName.DOORF3) == false;
            }
            else
            {
                if (idx == 0)
                {
                    if (SETTING.System.Disable_safty_F0) return true;
                    else return DIO.GetIOInput(eDIName.DOORF1) == false;
                }
                else if (idx == 1)
                {
                    if (AR.SETTING.System.Disable_safty_F1) return true;
                    else return DIO.GetIOInput(eDIName.DOORF2) == false;
                }
                else if (idx == 2)
                {
                    if (AR.SETTING.System.Disable_safty_F2) return true;
                    else return DIO.GetIOInput(eDIName.DOORF3) == false;
                }
            }
            return false;
        }

        public static Boolean isSaftyDoorR(int idx, Boolean RealSensor)
        {
            if (RealSensor == false && idx == 0 && AR.SETTING.System.Disable_safty_R0 == true) return true;
            else if (RealSensor == false && idx == 1 && AR.SETTING.System.Disable_safty_R1 == true) return true;
            else if (RealSensor == false && idx == 2 && AR.SETTING.System.Disable_safty_R2 == true) return true;
            else if (idx == 0 && DIO.GetIOInput(eDIName.DOORR1) == false) return true;
            else if (idx == 1 && DIO.GetIOInput(eDIName.DOORR2) == false) return true;
            else if (idx == 2 && DIO.GetIOInput(eDIName.DOORR3) == false) return true;
            else return false;
        }

        private static DateTime RoomLightControlTime = DateTime.Now;
        public static Boolean SetRoomLight(Boolean on, bool force = false)
        {
            if (on == true && AR.SETTING.Data.Disable_RoomLight == true && force == false)
            {
                PUB.log.Add("Disabled:ROOM Light");
                SetOutput(eDOName.ROOMLIGHT, false);// PUB.dio.SetOutput(Pin[eDOName.ROOMLIGHT].terminalno, false);
                return true; //200708
            }

            //형광등은 너무 빠른 제어는 하지 않는다
            var ts = DateTime.Now - RoomLightControlTime;
            if (ts.TotalMilliseconds < 500) return false;
            RoomLightControlTime = DateTime.Now;
            return SetOutput(eDOName.ROOMLIGHT, on);// PUB.dio.SetOutput(Pin[eDOName.ROOMLIGHT].terminalno, on);
        }
        public static Boolean SetAIR(Boolean ON)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            return SetOutput(eDOName.SOL_AIR, ON);//return PUB.dio.SetOutput(Pin[eDOName.SOL_AIR].terminalno, ON);

        }

        /// <summary>
        /// * 출력을 변경 합니다
        /// </summary>
        /// <param name="pin"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Boolean SetOutput(eDOName pin, Boolean value)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            var pindef = Pin[pin];
            return PUB.dio.SetOutput(pindef.terminalno, value);
        }

        public static bool GetPortMotorRun(int index)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            if (index < 0 || index > 3) throw new Exception("Port number must be entered between (0~2)");

            Boolean b1 = false;

            eDOName Pin_Dir = eDOName.PORTL_MOT_RUN;
            if (index == 1) Pin_Dir = eDOName.PORTC_MOT_RUN;
            else if (index == 2) Pin_Dir = eDOName.PORTR_MOT_RUN;

            //direction을 먼저 전송한다
            b1 = DIO.GetIOOutput(Pin_Dir);
            return b1;
        }

        public static eMotDir GetPortMotorDir(int index)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return eMotDir.CW;
            if (index < 0 || index > 3) throw new Exception("Port number must be entered between (0~2)");

            Boolean b1 = false;

            eDOName Pin_Dir = eDOName.PORTL_MOT_DIR;
            if (index == 1) Pin_Dir = eDOName.PORTC_MOT_DIR;
            else if (index == 2) Pin_Dir = eDOName.PORTR_MOT_DIR;

            //direction을 먼저 전송한다
            b1 = DIO.GetIOOutput(Pin_Dir);
            if (b1 == false) return eMotDir.CW;
            else return eMotDir.CCW;
        }

        public static Boolean SetPortMagnet(int index, Boolean on)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;

            //기능적용 2100129
            if (on == true)
            {
                if (index == 0 && AR.SETTING.Data.Enable_Magnet0 == false) return true;
                if (index == 1 && AR.SETTING.Data.Enable_Magnet1 == false) return true;
                if (index == 2 && AR.SETTING.Data.Enable_Magnet2 == false) return true;
            }

            if (index == 0) return DIO.SetOutput(eDOName.PORTL_MAGNET, on);
            else if (index == 1) return DIO.SetOutput(eDOName.PORTC_MAGNET, on);
            else return DIO.SetOutput(eDOName.PORTR_MAGNET, on);
        }
        /// <summary>
        /// CW = Up, CCW = Dn
        /// </summary>
        /// <param name="index"></param>
        /// <param name="Dir"></param>
        /// <param name="run"></param>
        /// <returns></returns>
        public static Boolean SetPortMotor(int index, eMotDir Dir, Boolean run, string remark, Boolean smalldown = false)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;

            //Pub.log.AddI($"포트모터({index}) {(Dir == eMotDir.CW ? "(정)" : "(역)")}방향 : {(run ? "O" : "X")} => {remark}");


            Boolean b1, b2; b1 = b2 = false;

            eDOName Pin_Dir, Pin_Run;
            eDIName pin_limp, pin_limn;

            if (index == 0) Pin_Dir = eDOName.PORTL_MOT_DIR;
            else if (index == 1) Pin_Dir = eDOName.PORTC_MOT_DIR;
            else Pin_Dir = eDOName.PORTR_MOT_DIR;

            if (index == 0) Pin_Run = eDOName.PORTL_MOT_RUN;
            else if (index == 1) Pin_Run = eDOName.PORTC_MOT_RUN;
            else Pin_Run = eDOName.PORTR_MOT_RUN;

            if (index == 0) pin_limp = eDIName.PORTL_LIM_UP;
            else if (index == 1) pin_limp = eDIName.PORTC_LIM_UP;
            else pin_limp = eDIName.PORTR_LIM_UP;

            if (index == 0) pin_limn = eDIName.PORTL_LIM_DN;
            else if (index == 1) pin_limn = eDIName.PORTC_LIM_DN;
            else pin_limn = eDIName.PORTR_LIM_DN;

            //direction을 먼저 전송한다            
            if (run)
            {

                //b2 = Pub.dio.SetOutput(Pin_Dir, Dir != eMotDir.CW);
                //System.Threading.Thread.Sleep(5);

                //켜야하는 상황인데.. 리밋이 걸렸다면 처리하지 않는다
                if (Dir == eMotDir.CW && DIO.GetIOInput(pin_limp) == true)
                {
                    PUB.log.AddI(string.Format("Ignoring output for port({0}) (LIMIT_UP) direction:{1}", index, Dir));
                    b1 = true;
                }
                else if (Dir == eMotDir.CCW && DIO.GetIOInput(pin_limn) == true)
                {
                    PUB.log.AddI(string.Format("Ignoring output for port({0}) (LIMIT_DN) direction:{1}", index, Dir));
                    b1 = true;
                }
                else
                {
                    if (smalldown)
                    {
                        if (index == 0)
                        {
                            PUB.flag.set(eVarBool.FG_PORT0_ENDDOWN, true, remark + ":SETPORT");
                            VAR.TIME.Update(eVarTime.PORT0); //내린시간
                        }
                        if (index == 1)
                        {
                            PUB.flag.set(eVarBool.FG_PORT1_ENDDOWN, true, remark + ":SETPORT");
                            VAR.TIME.Update(eVarTime.PORT1); //내린시간
                        }
                        if (index == 2)
                        {
                            PUB.flag.set(eVarBool.FG_PORT2_ENDDOWN, true, remark + ":SETPORT");
                            VAR.TIME.Update(eVarTime.PORT2); //내린시간
                        }
                        PUB.log.AddAT(string.Format("P{0} Small Down Active Dir={1}", index, Dir));
                    }
                    else
                    {
                        //다른곳에서 이동을 설정해버리면 sdmall down 기능을 없앤다 -- 210405
                        if (index == 0 && PUB.flag.get(eVarBool.FG_PORT0_ENDDOWN) == true)
                        {
                            PUB.flag.set(eVarBool.FG_PORT0_ENDDOWN, false, remark + ":SETPORT");
                            PUB.log.AddAT("P0 Small Down Ignore");
                        }
                        if (index == 1 && PUB.flag.get(eVarBool.FG_PORT1_ENDDOWN) == true)
                        {
                            PUB.flag.set(eVarBool.FG_PORT1_ENDDOWN, false, remark + ":SETPORT");
                            PUB.log.AddAT("P1 Small Down Ignore");
                        }
                        if (index == 2 && PUB.flag.get(eVarBool.FG_PORT2_ENDDOWN) == true)
                        {
                            PUB.flag.set(eVarBool.FG_PORT2_ENDDOWN, false, remark + ":SETPORT");
                            PUB.log.AddAT("P2 Small Down Ignore");
                        }
                    }

                    //방향전환을 해야한다면 우선 정지 후 500ms 대기한다
                    if (DIO.GetPortMotorDir(index) != Dir)
                    {
                        //일단 멈춤고
                        b1 = SetOutput(Pin_Run, false);// PUB.dio.SetOutput(Pin_Run, false);
                        System.Threading.Thread.Sleep(20);

                        //방향전환 ON
                        b2 = SetOutput(Pin_Dir, Dir != eMotDir.CW);
                        System.Threading.Thread.Sleep(20);

                        //모터 가동
                        b1 = SetOutput(Pin_Run, run);
                        System.Threading.Thread.Sleep(20);
                    }
                    else
                    {
                        //방향전환을 하지 않는 경우

                        //모터 가동
                        b2 = true;
                        b1 = SetOutput(Pin_Run, run);
                        System.Threading.Thread.Sleep(20);
                    }

                    //b1 = Pub.dio.SetOutput(Pin_Run, run);
                }
            }
            else
            {
                //동작을 먼저 끈다
                b1 = SetOutput(Pin_Run, run);
                System.Threading.Thread.Sleep(20);

                //방향핀을 끈다
                b2 = SetOutput(Pin_Dir, false);
                System.Threading.Thread.Sleep(20);
            }


            //System.Threading.Thread.Sleep(5);
            return b1 && b2;
        }

        public static Boolean SetPrintLAir(bool run, bool force = false)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            if (force == false && AR.SETTING.Data.Disable_PLAir == true) run = false;
            return SetOutput(eDOName.PRINTL_AIRON, run);
        }
        public static Boolean SetPrintRAir(bool run, bool force = false)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            if (force == false && AR.SETTING.Data.Disable_PRAir == true) run = false;
            return SetOutput(eDOName.PRINTR_AIRON, run);
        }


        public static Boolean SetPrintLVac(ePrintVac run, bool force = false)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            if (force == false && AR.SETTING.Data.Disable_PLVac == true) run = ePrintVac.off;
            bool b1, b2;
            if (run == ePrintVac.inhalation)
            {
                //흡기
                b1 = DIO.SetOutput(eDOName.PRINTL_VACO, false);
                b2 = DIO.SetOutput(eDOName.PRINTL_VACI, true);
            }
            else if (run == ePrintVac.exhaust)
            {
                //배기
                b1 = DIO.SetOutput(eDOName.PRINTL_VACI, false);
                b2 = DIO.SetOutput(eDOName.PRINTL_VACO, true);
            }
            else
            {
                //끄기
                b1 = DIO.SetOutput(eDOName.PRINTL_VACO, false);
                b2 = DIO.SetOutput(eDOName.PRINTL_VACI, false);
            }
            return b1 && b2;
        }
        public static Boolean SetPrintRVac(ePrintVac run, bool force = false)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            if (force == false && AR.SETTING.Data.Disable_PRVac == true) run = ePrintVac.off;
            bool b1, b2;
            if (run == ePrintVac.inhalation)
            {
                //흡기
                b1 = DIO.SetOutput(eDOName.PRINTR_VACO, false);
                b2 = DIO.SetOutput(eDOName.PRINTR_VACI, true);
            }
            else if (run == ePrintVac.exhaust)
            {
                //배기
                b1 = DIO.SetOutput(eDOName.PRINTR_VACI, false);
                b2 = DIO.SetOutput(eDOName.PRINTR_VACO, true);
            }
            else
            {
                //끄기
                b1 = DIO.SetOutput(eDOName.PRINTR_VACO, false);
                b2 = DIO.SetOutput(eDOName.PRINTR_VACI, false);
            }
            return b1 && b2;
        }
        public static Boolean SetPickerVac(Boolean run, Boolean force = false)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            // Pub.log.Add("[F] 진공 : " + run.ToString());
            bool b1, b2, b3, b4;
            //if (COMM.SETTING.Data.Disable_vacum) run = false;
            if (run)
            {
                if (force == true || AR.SETTING.Data.Disable_PKVac == false)
                {
                    b1 = SetOutput(eDOName.PICK_VAC1, true);
                    b2 = SetOutput(eDOName.PICK_VAC2, true);
                    b3 = SetOutput(eDOName.PICK_VAC3, true);
                    b4 = SetOutput(eDOName.PICK_VAC4, true);
                }
                else
                {
                    b1 = b2 = b3 = b4 = true;
                }
            }
            else
            {
                b1 = SetOutput(eDOName.PICK_VAC1, false);
                b2 = SetOutput(eDOName.PICK_VAC2, false);
                b3 = SetOutput(eDOName.PICK_VAC3, false);
                b4 = SetOutput(eDOName.PICK_VAC4, false);
                if (PUB.flag.get(eVarBool.FG_PK_ITEMON) == true)
                {
                    PUB.flag.set(eVarBool.FG_PK_ITEMON, false, "VACOFF");
                    PUB.logDbg.AddI("Picker item flag removed");
                }



            }
            return b1 & b2 & b3 & b4;
        }


        #region "Tower Lamp"

        /// <summary>
        /// 타워램프버튼 작업
        /// </summary>
        /// <param name="g"></param>
        /// <param name="r"></param>
        /// <param name="y"></param>
        public static void SetTWLamp(Boolean bFront, Boolean r, Boolean g, Boolean y)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return;

            if (DIO.GetIOOutput(eDOName.TWR_GRNF) != g) SetOutput(eDOName.TWR_GRNF, g);
            if (DIO.GetIOOutput(eDOName.TWR_REDF) != r) SetOutput(eDOName.TWR_REDF, r);
            if (DIO.GetIOOutput(eDOName.TWR_YELF) != y) SetOutput(eDOName.TWR_YELF, y);

            if (PUB.flag.get(eVarBool.FG_MOVE_PICKER) == true)
            {
                g = true;
                r = true;
                if (DIO.GetIOOutput(eDOName.BUT_STARTF) != g) SetOutput(eDOName.BUT_STARTF, g);
                if (DIO.GetIOOutput(eDOName.BUT_STOPF) != r) SetOutput(eDOName.BUT_STOPF, r);
            }
            else
            {
                if (DIO.GetIOOutput(eDOName.BUT_STARTF) != g) SetOutput(eDOName.BUT_STARTF, g);
                if (DIO.GetIOOutput(eDOName.BUT_STOPF) != r) SetOutput(eDOName.BUT_STOPF, r);
            }
            if (DIO.GetIOOutput(eDOName.BUT_RESETF) != y) SetOutput(eDOName.BUT_RESETF, y);
        }

        public static Boolean SetTwRed(Boolean ON)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            SetOutput(eDOName.BUT_STOPF, ON);
            return SetOutput(eDOName.TWR_REDF, ON);

        }
        public static Boolean SetTwYel(Boolean ON)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            SetOutput(eDOName.BUT_RESETF, ON);
            return SetOutput(eDOName.TWR_YELF, ON);

        }
        public static Boolean SetTwGrn(Boolean ON)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            SetOutput(eDOName.BUT_STARTF, ON);
            return SetOutput(eDOName.TWR_GRNF, ON);
        }

        #endregion

        public static Boolean SetBuzzer(Boolean ON, bool force = false)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            if (ON)
            {
          
                if (SETTING.Data.Disable_Buzzer == true && force == false) return true; //Not used when buzzer function is OFF
            }

            if (ON && SETTING.Data.Disable_Buzzer == true && force == false)
            {
                PUB.log.AddAT("buzzer Disabled");
                ON = false;
            }

            return SetOutput(eDOName.BUZZER, ON);
        }
        public static Boolean SetMotPowerOn(Boolean ON)
        {
            if (PUB.dio == null || !PUB.dio.IsInit) return false;

            var c0 = !DIO.GetIOOutput(eDOName.SVR_PWR_0);
            var c1 = !DIO.GetIOOutput(eDOName.SVR_PWR_1);
            var c2 = !DIO.GetIOOutput(eDOName.SVR_PWR_2);
            var c3 = !DIO.GetIOOutput(eDOName.SVR_PWR_3);
            var c4 = !DIO.GetIOOutput(eDOName.SVR_PWR_4);
            var c5 = !DIO.GetIOOutput(eDOName.SVR_PWR_5);
            var c6 = !DIO.GetIOOutput(eDOName.SVR_PWR_6);

            //꺼져잇는 신호가 하나도 없다면 이번에 끄니깐 메세지를 추가하자
            //if (c0 == false && c0 == c1 && c0 == c2 && c0 == c3 && c0 == c4 && c0 == c5 && c0 == c6)
            //    Console.WriteLine("mot power off");


            bool b0, b1, b2, b3, b4, b5, b6;
            b0 = b1 = b2 = b3 = b4 = b5 = b6 = true;

            if (c0 != ON) b0 = SetOutput(eDOName.SVR_PWR_0, !ON);
            if (c1 != ON) b1 = SetOutput(eDOName.SVR_PWR_1, !ON);
            if (c2 != ON) b2 = SetOutput(eDOName.SVR_PWR_2, !ON);
            if (c3 != ON) b3 = SetOutput(eDOName.SVR_PWR_3, !ON);
            if (c4 != ON) b4 = SetOutput(eDOName.SVR_PWR_4, !ON);
            if (c5 != ON) b5 = SetOutput(eDOName.SVR_PWR_5, !ON);
            if (c6 != ON) b6 = SetOutput(eDOName.SVR_PWR_6, !ON);

            return b0 && b1 && b2 && b3 && b4 && b5 && b6;
        }
        public static Boolean SetMotEmergency(Boolean ON)
        {
            //if (ON == true) Console.WriteLine("mot emg on");
            if (PUB.dio == null || !PUB.dio.IsInit) return false;
            return true;

            //var c0 = DIO.GetIOOutput(eDOName.SVR_EMG_0);
            //var c1 = DIO.GetIOOutput(eDOName.SVR_EMG_1);
            //var c2 = DIO.GetIOOutput(eDOName.SVR_EMG_2);
            //var c3 = DIO.GetIOOutput(eDOName.SVR_EMG_3);
            //var c4 = DIO.GetIOOutput(eDOName.SVR_EMG_4);
            //var c5 = DIO.GetIOOutput(eDOName.SVR_EMG_5);
            //var c6 = DIO.GetIOOutput(eDOName.SVR_EMG_6);

            //bool b0, b1, b2, b3, b4, b5, b6;
            //b0 = b1 = b2 = b3 = b4 = b5 = b6 = ON;

            //if (c0 != ON) b0 = PUB.dio.SetOutput(Pin[eDOName.SVR_EMG_0) - 1, ON);
            //if (c1 != ON) b1 = PUB.dio.SetOutput(Pin[eDOName.SVR_EMG_1) - 1, ON);
            //if (c2 != ON) b2 = PUB.dio.SetOutput(Pin[eDOName.SVR_EMG_2) - 1, ON);
            //if (c3 != ON) b3 = PUB.dio.SetOutput(Pin[eDOName.SVR_EMG_3) - 1, ON);
            //if (c4 != ON) b4 = PUB.dio.SetOutput(Pin[eDOName.SVR_EMG_4) - 1, ON);
            //if (c5 != ON) b5 = PUB.dio.SetOutput(Pin[eDOName.SVR_EMG_5) - 1, ON);
            //if (c6 != ON) b6 = PUB.dio.SetOutput(Pin[eDOName.SVR_EMG_6) - 1, ON);
            //return b0 && b1 && b2 && b3 && b4 && b5 && b6;
        }

    }
}
