using Aitex.Core.RT.Device;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.Routine;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Beckhoff.Station;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Layout;
using MECF.Framework.Common.Routine;
using MECF.Framework.Common.Utilities;
using MECF.Framework.Common.WaferHolder;
using CyberX8_Core;
using CyberX8_RT.Devices.AXIS;
using CyberX8_RT.Devices.AXIS.CANOpen;
using CyberX8_RT.Devices.Facilities;
using CyberX8_RT.Devices.Loader;
using CyberX8_RT.Devices.TransPorter;
using CyberX8_RT.Modules.Loader;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CyberX8_RT.Devices.Rinse;
using CyberX8_RT.Devices.Metal;
using Aitex.Core.Common;
namespace CyberX8_RT.Modules.Transporter
{
   
    public class TransporterPickUpFromRoutine : RoutineBase, IRoutine
    {
        private enum PickUpStep
        {
            CheckPreCondition,
            TargetCellUnclamp,
            TargetCellUnclampWait,
            DropBlockLockoff,
            ElevatorGotoUp,
            ElevatorGotoUpWait,
            SafeMoveTo,
            CheckMoveToStatus,
            GantryPosition,
            GantryPoisitionWait,           
            ElevatorPositionToCell,
            ElevatorPositionToCellWait,
            Delay,
            DropBlockLockOn, 
            CalculateLiftupSpeed,
            PickupDelay,
            ElevatorPositionToUp,
            ElevatorPositionToUpWait,
            UpdateWaferShuttle,
            CheckWSPresent,
            //ReadBarcodeConfirm,
            End
        }
        #region 内部变量
        private string _cellName;
        private JetAxisBase _gantryAxis;
        private JetAxisBase _elevatorAxis;
        private JetAxisBase _loaderRotationAxis;
        private SystemFacilities _facilities;
        private TransporterConflictRoutine _conflictRoutine;
        private LoaderPreTransferUnclampRoutine _preTransferUnclampRoutine;
        private TransporterCommon _transporterCommon;
        private LoaderCommonDevice _loaderCommonDevice;
        ProcessLayoutCellItem _cellItem;
        private int _pickupTime;
        private int _pickupDelayTime;
        private int _velocity;
        private int _acceleration;
        private bool _bypassWaferHolderPresent;
        private int _pickMaxRetries = 2;
        #endregion
        #region 属性
        public string SourceCell { get { return _cellName; } }
        #endregion
        /// 
        /// 构造函数
        /// 
        /// 
        public TransporterPickUpFromRoutine(string module) : base(module)
        {
        }
        /// 
        /// 中止
        /// 
        public void Abort()
        {
            Runner.Stop("Manual Abort");
        }
        /// 
        /// 监控
        /// 
        /// 
        public RState Monitor()
        {
            Runner.Run(PickUpStep.CheckPreCondition, CheckStartPreConfition, _delay_1ms)
                .Run(PickUpStep.TargetCellUnclamp, TargetCellUnclamp, _delay_1ms)
                .WaitWithStopCondition(PickUpStep.TargetCellUnclampWait, TargetCellUnclampEndStatus, TargetCellUnclampStopStatus)
                //1. 确认DropBlockLock是否off
                .Run(PickUpStep.DropBlockLockoff, DropBlockLockoff, _delay_1ms)
                //2. Elevator go to up
                .Run(PickUpStep.ElevatorGotoUp, ElevatorGotoUP, _delay_1ms)
                .WaitWithStopCondition(PickUpStep.ElevatorGotoUpWait, CheckElevatorPositionEndStatus, CheckElevatorPositionEndStatus)
                //3. other Transporter Safe Move 
                .Run(PickUpStep.SafeMoveTo, SafeMoveTo, _delay_1ms)
                .WaitWithStopCondition(PickUpStep.CheckMoveToStatus, () => CommonFunction.CheckRoutineEndState(_conflictRoutine),
                CheckSafeMoveToStopStatus)
                //4. Gantry 移动到目标位置
                .Run(PickUpStep.GantryPosition, GantryPositionToCell, _delay_1ms)
                .WaitWithStopCondition(PickUpStep.GantryPoisitionWait, CheckGantryPositionStatus, CheckGantryPositionRunStop)                
                //5. Elevator 移动至对应cell位
                .Run(PickUpStep.ElevatorPositionToCell, ElevatorPositionToCell, _delay_1ms)
                .WaitWithStopCondition(PickUpStep.ElevatorPositionToCellWait, CheckElevatorPositionEndStatus, CheckElevatorPositionStopStatus)
                .Delay(PickUpStep.Delay,500)
                //6. Drop Block Lock on,抓取WS
                .Run(PickUpStep.DropBlockLockOn, DropBlockLockon, _delay_1ms)              
                //7. 确认Elevator lift speed
                .Run(PickUpStep.CalculateLiftupSpeed,CalculateLiftupSpeed,_delay_1ms)
                //8. Pickup delay
                .Delay(PickUpStep.PickupDelay,_pickupDelayTime * 1000)
                //9. Elevator goto Up
                 .Run(PickUpStep.ElevatorPositionToUp, ElevatorGotoUP, 100)
                .WaitWithStopCondition(PickUpStep.ElevatorPositionToUpWait, CheckElevatorPositionEndStatus, CheckElevatorPositionStopStatus)
                //10. 确认Transporter的Wafer shuttle hold present信号为on
                .Wait(PickUpStep.CheckWSPresent, CheckWSPresent, _delay_2s)
                //11. Material Tracking Update
                .Run(PickUpStep.UpdateWaferShuttle, WaferShuttleTransfer,_delay_1ms)               
                //12. Read Barcode 确认与Material Tracking的转移是否一致
                //.Run(PickUpStep.ReadBarcodeConfirm,ReadBarcode,_delay_1ms)
                .End(PickUpStep.End,NullFun,100);
            return Runner.Status;
        }
        /// 
        /// 目标cell unclamp
        /// 
        /// 
        private bool TargetCellUnclamp()
        {
            if (_cellName == "Loader")
            {
                bool result = _preTransferUnclampRoutine.Start() == RState.Running;
                if (!result)
                {
                    NotifyError(eEvent.ERR_TRANSPORTER, "Loader Unclamp failed", 0);
                }
                return result;
            }
            else
            {
                _cellItem = ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName);
                if (_cellItem != null)
                {
                    bool result = false;
                    if (Enum.TryParse(_cellItem.ModuleName, out ModuleName cellModuleName))
                    {
                        if (ModuleHelper.IsRinse(cellModuleName))
                        {
                            RinseDevice rinseDevice = DEVICE.GetDevice(_cellItem.ModuleName);
                            if (rinseDevice != null)
                            {
                                result = rinseDevice.WaferHolderClampValveOff();
                                if (!result)
                                {
                                    NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellItem.ModuleName} Clamp off failed", 0);
                                }
                                return result;
                            }
                        }
                        else if (ModuleHelper.IsMetal(cellModuleName))
                        {
                            MetalCellDevice metalCellDevice = DEVICE.GetDevice(_cellItem.ModuleName);
                            if (metalCellDevice != null)
                            {
                                result = metalCellDevice.WaferHolderClampOff();
                                if (!result)
                                {
                                    NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellItem.ModuleName} Clamp off failed", 0);
                                }
                                return result;
                            }
                        }
                    }
                }
            }
            return true;
        }
        /// 
        /// 目标Cell Unclamp状态
        /// 
        /// 
        private bool TargetCellUnclampEndStatus()
        {
            if (_cellName == "Loader")
            {
                return CommonFunction.CheckRoutineEndState(_preTransferUnclampRoutine);
            }
            else
            {
                _cellItem = ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName);
                if (_cellItem != null)
                {
                    if (Enum.TryParse(_cellItem.ModuleName, out ModuleName cellModuleName))
                    {
                        if (ModuleHelper.IsRinse(cellModuleName))
                        {
                            RinseDevice rinseDevice = DEVICE.GetDevice(_cellItem.ModuleName);
                            if (rinseDevice != null)
                            {
                                return !rinseDevice.RinseData.WaferHolderClamp;
                            }
                        }
                        else if (ModuleHelper.IsMetal(cellModuleName))
                        {
                            MetalCellDevice metalCellDevice = DEVICE.GetDevice(_cellItem.ModuleName);
                            if (metalCellDevice != null)
                            {
                                return metalCellDevice.ClampOff;
                            }
                        }
                    }
                }
            }
            return true;
        }
        /// 
        /// 目标Cell Unclamp运行中止状态
        /// 
        /// 
        private bool TargetCellUnclampStopStatus()
        {
            if (_cellName == "Loader")
            {
                bool result = CommonFunction.CheckRoutineStopState(_preTransferUnclampRoutine);
                if (result)
                {
                    NotifyError(eEvent.ERR_TRANSPORTER, "Loader Unclamp failed", 0);
                }
                return result;
            }
            return false;
        }
        /// 
        /// 关闭DropBlockLock
        /// 
        /// 
        private bool DropBlockLockoff()
        {
            if (_transporterCommon.TransporterData.Lock)
            {
                return _transporterCommon.UnlockOperation("", null);
            }       
            return true;
        }
        /// 
        /// 打开DropBlockLock
        /// 
        /// 
        private bool DropBlockLockon()
        {
            if (!_transporterCommon.TransporterData.Lock)
            {
                return _transporterCommon.LockOperation("", null);
            }
            return true;
        }
        /// 
        /// 安全避障移动
        /// 
        /// 
        private bool SafeMoveTo()
        {
            _cellItem = ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName);
            string stationName = _cellName;
            if (_cellItem != null)
            {
                if (_cellName.ToLower() != "loader" && _cellName.ToLower() != "park")
                {
                    stationName = $"Cell{_cellItem.CellId}";
                }
            }
            else
            {
                NotifyError(eEvent.ERR_TRANSPORTER,  $"{_cellName} not in layout", 0);
                return false;
            }
            var result = _gantryAxis.GetPositionByStation(stationName);
            if(result.success)
            {
                bool isPositive = false;
                if(_gantryAxis.MotionData.MotorPosition
        /// 检验安全避让异常结束状态
        /// 
        /// 
        private bool CheckSafeMoveToStopStatus()
        {
            bool result = CommonFunction.CheckRoutineStopState(_conflictRoutine);
            if (result)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, "Safe Move failed", 0);
            }
            return result;
        }
        /// 
        /// Gantry Position To cell
        /// 
        /// 
        private bool GantryPositionToCell()
        {
            _cellItem= ProcessLayoutManager.Instance.GetProcessLayoutCellItemByModuleName(_cellName);
            bool result = false;
            if (_cellItem != null)
            {
                if (_cellName.ToLower() != "loader"&&_cellName.ToLower()!="park")
                {
                    result= _gantryAxis.PositionStation($"Cell{_cellItem.CellId}", false);
                }
                else
                {
                    result= _gantryAxis.PositionStation(_cellName,false);
                }
                if (!result)
                {
                    NotifyError(eEvent.ERR_TRANSPORTER, "gantry axis motion failed", 0);
                }
                return result;
            }
            else
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellName} not in layout", 0);
                return false;
            }
        }
        /// 
        /// Elevator Position to cell
        /// 
        /// 
        private bool ElevatorPositionToCell()
        {
            bool result = false;
            if( _cellItem != null )
            {
                if (_cellName.ToLower()!="loader")
                {
                    result= _elevatorAxis.PositionStation($"Cell{_cellItem.CellId}", false);
                }
                else
                {
                    result= _elevatorAxis.PositionStation(_cellName, false);
                }
                if (!result)
                {
                    NotifyError(eEvent.ERR_TRANSPORTER, "elevator axis motion failed", 0);
                }
                return result;
            }
            else
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellName} not in layout",0);
                return false;
            }
        }
        /// 
        /// 检验Vertical移动状态
        /// 
        /// 
        private bool CheckElevatorPositionEndStatus()
        {
            return _elevatorAxis.Status == RState.End;
        }
        /// 
        /// 检验Vertical是否还在运动
        /// 
        /// 
        private bool CheckElevatorPositionStopStatus()
        {
            bool result = _elevatorAxis.Status == RState.Failed || _elevatorAxis.Status == RState.Timeout ;
            if (result)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, "elevator axis motion failed",0);
            }
            return result;
        }
        /// 
        /// 检验Gantry移动状态
        /// 
        /// 
        private bool CheckGantryPositionStatus()
        {
            return _gantryAxis.Status == RState.End;
        }
        /// 
        /// 检验Gantry是否还在运动
        /// 
        /// 
        private bool CheckGantryPositionRunStop()
        {
            bool result= _gantryAxis.Status == RState.Failed||_gantryAxis.Status==RState.Timeout;
            if(result)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, "Gantry Motion failed", 0);
            }
            return result;
        }        
        /// 
        /// 计算提升速度
        /// 
        /// 
        private bool CalculateLiftupSpeed()
        {
            if(_pickupTime==0)
            {
                return true;
            }  
            BeckhoffStationAxis stationAxis = BeckhoffStationLocationManager.Instance.GetStationAxis(Module, "Elevator");
            Station upStation = stationAxis.Stations.Find(O => O.Name.EndsWith("UP"));
            Station cellStation = null;
            if (_cellName == "Loader")
            {
                cellStation = stationAxis.Stations.Find(O => O.Name.EndsWith("Loader"));
            }
            else
            {
                cellStation = stationAxis.Stations.Find(O => O.Name.EndsWith($"Cell{_cellItem.CellId}"));
            }
            if(upStation==null)
            {
                NotifyError(eEvent.ERR_TRANSPORTER,  "UP is not in Station List",0);
                return false;
            }
            if(cellStation==null)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"Cell{_cellItem.CellId} is not in Station List",0);
                return false;
            }
            if(!double.TryParse(cellStation.Position,out double cellStationPosition))
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"Cell{_cellItem.CellId} Station Position is invalid",0);
                return false;
            }
            if (!double.TryParse(upStation.Position, out double upStationPosition))
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"Cell{_cellItem.CellId} Station Position is invalid", 0);
                return false;
            }
            int distance =(int)Math.Round(Math.Abs(cellStationPosition - upStationPosition));
            double tmpVelocity = (double) distance/ _pickupTime;
            _velocity = _elevatorAxis.CalculateMultiplySpeedRatio(_elevatorAxis.CalculateValueMultiplyScale(tmpVelocity));
            double tmpAccelaration = (double)(2 * distance) / Math.Pow(_pickupTime, 2);
            _acceleration = _elevatorAxis.CalculateMultiplyAccelerationRatio(_elevatorAxis.CalculateValueMultiplyScale(tmpAccelaration));
            LOG.WriteBackgroundLog(eEvent.INFO_TRANSPORTER, Module, "adjust profile speed");
            return true;
        }
        /// 
        /// Elevator运动至UP
        /// 
        /// 
        private bool ElevatorGotoUP()
        {
            bool result= _elevatorAxis.PositionStation("UP", false, _velocity, _acceleration, _acceleration);
            if(!result)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, "elevator goto up failed",0);
            }
            return result;
        }
        /// 
        /// 更新WaferHolder移动信息
        /// 
        /// 
        private bool WaferShuttleTransfer()
        {
            bool isMetal = false;
            DateTime lastMetalRecipeTime = DateTime.Now;
            if(Enum.TryParse(_cellName,out ModuleName moduleName)&&ModuleHelper.IsMetal(moduleName))
            {
                isMetal = true;
                WaferHolderInfo info = WaferHolderManager.Instance.GetWaferHolder(_cellName);
                if (info != null)
                {
                    lastMetalRecipeTime = info.LastMetalRecipeCompleteTime;
                }
            }
            bool result= WaferHolderManager.Instance.TransferWaferHolder(Module,_cellName, Module,false);
            if (!result)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, "tranfer waferHolder message failed", 0);
            }
            else
            {                
                SwitchWafer(_cellName, Module);
                if (!Singleton.Instance.IsAutoRunning)
                {
                    return true;
                }
                WaferHolderInfo waferHolderInfo = WaferHolderManager.Instance.GetWaferHolder(Module);
                if (waferHolderInfo == null)
                {
                    return true;
                }
                string strTime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
                waferHolderInfo.SchedulerModules.Add($"{strTime} {_cellName} => {Module}");
                if (isMetal)
                {
                    int waferShuttleSoakMaxTime = SC.GetValue("Metal.WaferShuttleSoakMaxTime");
                    double soakTime = Math.Round(DateTime.Now.Subtract(lastMetalRecipeTime).TotalMinutes,2);
                    if (soakTime > waferShuttleSoakMaxTime)
                    {
                        LOG.WriteLog(eEvent.WARN_METAL, _cellName, $"time of {waferHolderInfo.Id} soak in metal is {soakTime} minute over {waferShuttleSoakMaxTime}");
                    }
                    else
                    {
                        LOG.WriteLog(eEvent.INFO_METAL, _cellName, $"time of {waferHolderInfo.Id} soak in metal is {soakTime} minute");
                    }
                }
            }
            return result;
        }
        /// 
        /// 交换Wafer
        /// 
        /// 
        /// 
        private void SwitchWafer(string from, string to)
        {
            TransporterEntity transporterEntity = Singleton.Instance.GetModule(Module);
            if (transporterEntity != null)
            {
                transporterEntity.SwitchWafer(from, to);
            }
        }
        /// 
        /// 检验WHPresent与Lock状态
        /// 
        /// 
        private bool CheckWSPresent()
        {
            bool locked = _transporterCommon.TransporterData.Lock;
            bool whPresent= _transporterCommon.TransporterData.WSHoldPresent;
            bool result= locked && (whPresent||_bypassWaferHolderPresent);
            if (!result)
            {
                LOG.WriteLog(eEvent.INFO_TRANSPORTER, Module, "check wafer Shuttle present and locked failed");
            }
            return result;
        }
        /// 
        /// 读取条码
        /// 
        /// 
        private bool ReadBarcode()
        {
            string str=_transporterCommon.ReaderBarcode();
            str = str.Trim();
            if(!string.IsNullOrEmpty(str))
            {
                TransporterEntity transporterEntity = Singleton.Instance.GetModule(Module.ToString());
                if (transporterEntity == null)
                {
                    return true;
                }
                WaferHolderInfo waferHolderInfo = transporterEntity.WaferHolderInfo;
                if (waferHolderInfo == null)
                {
                    return true;
                }
                if (waferHolderInfo.Id == str)
                {
                    return true;
                }
                WaferHolderManager.Instance.SwitchWaferHolderId(waferHolderInfo,Module,str);
                return true;
            }
            return true;
        }
        /// 
        /// 启动
        /// 
        /// 
        /// 
        public RState Start(params object[] objs)
        {
            _cellName = objs[0].ToString();
            _elevatorAxis = DEVICE.GetDevice($"{Module}.Elevator");;
            _gantryAxis = DEVICE.GetDevice($"{Module}.Gantry");            
            _loaderRotationAxis = DEVICE.GetDevice($"{ModuleName.Loader1}.Rotation");
            _conflictRoutine = new TransporterConflictRoutine(Module);
            _transporterCommon = DEVICE.GetDevice($"{Module}.Common");
            _loaderCommonDevice = DEVICE.GetDevice($"{ModuleName.Loader1}.Common");
            _bypassWaferHolderPresent = SC.GetValue("Transporter.BypassWaferHolderPresent");
            _preTransferUnclampRoutine = new LoaderPreTransferUnclampRoutine(ModuleName.Loader1.ToString());
            _velocity = 0;
            _acceleration = 0;
            _pickMaxRetries = SC.GetValue("Transporter.MaxPickTries");
            string preConfig = SC.GetConfigPreContent(_cellName);
            if (SC.ContainsItem($"{preConfig}.PickTimeSeconds"))
            {
                _pickupTime = SC.GetValue($"{preConfig}.PickTimeSeconds");
            }
            if (SC.ContainsItem($"{preConfig}.PickDelaySeconds"))
            {
                _pickupDelayTime = SC.GetValue($"{preConfig}.PickDelaySeconds");
            }
            return Runner.Start(Module, $"PickUpFrom {_cellName}");
        }
        
        /// 
        /// 启动校验条件
        /// 
        /// 
        private bool CheckStartPreConfition()
        {
            //所有轴上电并Homed
            bool result = CheckPreCondition();
            if(!result)
            {
                return false;
            }        
            //Transporter的Wafer shuttle hold present信号为off
            if (!_bypassWaferHolderPresent && _transporterCommon.TransporterData.WSHoldPresent)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} WaferShuttleHoldPresent is on", -1);
                return false;
            }
            //Loader is Home
            if (ModuleHelper.IsInstalled(ModuleName.Loader1))
            {
                //Loader is Home
                LoaderEntity loaderEntity = Singleton.Instance.GetModule(ModuleName.Loader1.ToString());
                if (loaderEntity != null && !loaderEntity.IsHomed)
                {
                    NotifyError(eEvent.ERR_TRANSPORTER, $"{ModuleName.Loader1} is not homed", -1);
                    return false;
                }
            }              
            //若目标Cell为Loader, 则Loader需在TRNA或TRANB位置且WaferShuttlePresent信号on
            if (_cellName == "Loader")
            {
                double loaderRotationPosition = _loaderRotationAxis.MotionData.MotorPosition;
                if (!_loaderRotationAxis.CheckPositionIsInStation(loaderRotationPosition, "TRNPA") && 
                    !_loaderRotationAxis.CheckPositionIsInStation(loaderRotationPosition, "TRNPB"))
                {
                    NotifyError(eEvent.ERR_TRANSPORTER, $"{ModuleName.Loader1} rotation axis {loaderRotationPosition} is not int TRNPA or TRNPB station",-1);
                    return false;
                }
                if(!_loaderCommonDevice.CommonData.WaferHolderPresent)
                {
                    NotifyError(eEvent.ERR_TRANSPORTER, $"{ModuleName.Loader1} WaferShuttlePresent is off", -1);
                    return false;
                }
            }
            //Transporter没有WS信息
            if (WaferHolderManager.Instance.HasWaferHolder(Module))
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} already has wafer Shuttle", -1);
                return false;
            }
            //目标Cell应有WS信息
            if (!WaferHolderManager.Instance.HasWaferHolder(_cellName))
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{_cellName} does not has wafer shuttle", -1);
                return false;
            }
            //检验Facilities
            //var faciltiesResult = _facilities.CheckCDA();
            //if (!faciltiesResult.result)
            //{
            //    NotifyError(eEvent.ERR_TRANSPORTER, faciltiesResult.reason, -1);
            //    return false;
            //}
            return true;
        }
        /// 
        /// 检验前置条件
        /// 
        /// 
        private bool CheckPreCondition()
        {
            if (!_gantryAxis.IsSwitchOn)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} gantry axis is not switch on ", -1);
                return false;
            }
            if (!_gantryAxis.IsHomed)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} gantry axis is not homed ",-1);
                return false;
            }
            if (!_elevatorAxis.IsSwitchOn)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} elevator axis is not switch on ", -1);
                return false;
            }
            if (!_elevatorAxis.IsHomed)
            {
                NotifyError(eEvent.ERR_TRANSPORTER, $"{Module} elevator axis is not homed ",-1);
                return false;
            }
            return true;
        }
    }
}