/// <summary>
        /// Internal Update Loop
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void UpdateLoop(object sender, DoWorkEventArgs e)
        {
            PIVarDirection dir      = PIVarDirection.ePI_INPUT;
            VAR_TYPE       varT     = VAR_TYPE.S_BYTE;
            PI_VAR_UNION   varUnion = new PI_VAR_UNION();

            do
            {
                try
                {
                    Thread.Sleep(LoopInterval);
                    KeyValuePair <CompBase, MMCSingleAxis>[] pairs = listAxis.ToArray();
                    foreach (KeyValuePair <CompBase, MMCSingleAxis> pair in pairs)
                    {
                        try
                        {
                            if (pair.Key is IOBoolChannel)
                            {
                                BoolInput[] inputs = pair.Key.RecursiveFilterByType <BoolInput>();
                                foreach (BoolInput input in inputs)
                                {
                                    pair.Value.ReadPIVar((UInt16)(input.Channel), dir, varT, ref varUnion);

                                    if (varUnion.s_byte == 1)
                                    {
                                        input.Value = true;
                                    }
                                    else
                                    {
                                        input.Value = false;
                                    }
                                }
                            }
                            else
                            {
                                double dVal = pair.Value.GetActualPosition();
                                if (pair.Key is RealAxis)
                                {
                                    (pair.Key as RealAxis).SetCurrentPosition(dVal);
                                    (pair.Key as RealAxis).MoveDone = IsMotionDone(pair.Value);
                                }
                                else if (pair.Key is RealRotary)
                                {
                                    (pair.Key as RealRotary).SetCurrentPosition(dVal);
                                    (pair.Key as RealRotary).MoveDone = IsMotionDone(pair.Value);
                                }
                                BoolInput[] inputs = pair.Key.RecursiveFilterByType <BoolInput>();
                                foreach (BoolInput input in inputs)
                                {
                                    input.Value = pair.Value.GetDigInput(input.Channel + 16) != 0;
                                }
                            }


                            MC_STATE_SINGLE status = (MC_STATE_SINGLE)(pair.Value.ReadStatus() & plcStateMask);
                            if ((status & MC_STATE_SINGLE.ERROR_STOP) == MC_STATE_SINGLE.ERROR_STOP)
                            {
                                pair.Key.MachineStatus(string.Format("{0} ErrorStop", pair.Value.AxisName));
                            }
                        }
                        catch (MMCException ex)
                        {
                            U.LogPopup(ex, "MMC Update Error Axis {0}", pair.Key.Name);
                        }
                    }
                }
                catch (Exception ex)
                {
                    U.LogError(ex, "Error UpdateLoop: ");
                }
            } while (!_destroy);
        }
        /// <summary>
        /// Set a digital output
        /// </summary>
        /// <param name="boolOutput"></param>
        /// <param name="value"></param>
        public override void Set(BoolOutput boolOutput, bool value)
        {
            VAR_TYPE     varT     = VAR_TYPE.BYTE_ARR;
            PI_VAR_UNION varUnion = new PI_VAR_UNION();


            CompBase compAxis = boolOutput.GetParent <RealAxis>();

            if (compAxis == null)
            {
                compAxis = boolOutput.GetParent <RealRotary>();
                if (compAxis == null)
                {
                    compAxis = boolOutput.GetParent <IOBoolChannel>();
                }
            }


            if (listAxis.ContainsKey(compAxis))
            {
                try
                {
                    MMCSingleAxis singleAxis = listAxis[compAxis];

                    if (compAxis is RealRotary)
                    {
                        int val = value ? 1 : 0;
                        //singleAxis.SetDigOutputs(boolOutput.Channel << 16, (byte)(value ? 0x1 : 0x0), 0x0);
                        singleAxis.SendIntCmdViaSDO(string.Format("OB[{0}]={1}", boolOutput.Channel, val), 1000);
                    }
                    else if (compAxis is RealAxis)
                    {
                        uint val     = outputVal[compAxis];
                        uint chanBit = (uint)(1 << (16 + boolOutput.Channel));
                        if (value)
                        {
                            val |= chanBit;
                        }
                        else
                        {
                            val &= ~chanBit;
                        }
                        singleAxis.SetDigOutputs32Bit(0, val);
                        outputVal[compAxis] = val;
                    }

                    else
                    {
                        UInt16 index = (UInt16)boolOutput.Channel;

                        if (value)
                        {
                            varUnion.s_byte = 0;
                        }
                        else
                        {
                            varUnion.s_byte = 1;
                        }
                        singleAxis.WritePIVar(index, varUnion, varT);
                    }

                    boolOutput.Value = value;
                    //singleAxis.SetDigOutputs(chan, (byte)(value ? 1 : 0), (byte)1);
                }
                catch (Exception ex)
                {
                    U.LogPopup(ex, "Trouble setting Digital Output ({0})", boolOutput.Name);
                }
            }
        }