diff --git a/Common/Production/ProductionUiCordonel/FinalTest.xaml.cs b/Common/Production/ProductionUiCordonel/FinalTest.xaml.cs index 4e1fae51..6fecf460 100644 --- a/Common/Production/ProductionUiCordonel/FinalTest.xaml.cs +++ b/Common/Production/ProductionUiCordonel/FinalTest.xaml.cs @@ -178,7 +178,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel try { - _processCtrl = new EolProcessController(Slot); + _processCtrl = new EolStateMachine(Slot); } catch (Exception ex) { diff --git a/Common/Production/ProductionUiCordonel/Picking.xaml.cs b/Common/Production/ProductionUiCordonel/Picking.xaml.cs index 72e42923..7ec51aff 100644 --- a/Common/Production/ProductionUiCordonel/Picking.xaml.cs +++ b/Common/Production/ProductionUiCordonel/Picking.xaml.cs @@ -178,7 +178,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel try { - _processCtrl = new EolProcessController(Slot); + _processCtrl = new EolStateMachine(Slot); } catch (Exception ex) { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessController.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessController.cs index 8ddac59b..c3783ef1 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessController.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProcessController.cs @@ -297,13 +297,200 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses /// private void TmrProcessCtrlCycle_Elapsed(Object state) { - StateMachine(); + GenericStateMachine(); } #endregion --------------------------------------- Events ----------------------------------------------------- #region ------------------------------------------ State Machine ---------------------------------------------- - public abstract void StateMachine(); + /// + public abstract void IndividualStateMachine(IProductionProcess process); + + /// + /// State machine of ProcessController which serves as template for all production processes. + /// + /// + /// INSTRUCTION FOR NORMAL USAGE: + /// ----------------------------- + /// Call the SetupProcess() with the + /// - new process automatically collected from with new + /// _actualProcessState as input, + /// - successExitState set to the next required state after successfully execution. + /// That's it! The normal state change has always only one production process active and waits for completion + /// before changing to a new state and therefore a new production process. + /// + /// If a special state is needed on errorExitState or breakExitState these can be assigned. Otherwise, the + /// errorExitState is linked to the error state, the breakExitState to the stop state. + /// + /// + /// INSTRUCTION FOR NON-BLOCKING MULTIPLE PROCESSES SIMULTANEOUSLY ACTIVITIES: + /// -------------------------------------------------------------------------- + /// Sometimes production processes may be able to be executed simultaneously as they are independent of each + /// other. One example is a database access for data collection from different tables. + /// + /// Call the SetupProcess with the + /// - new process automatically collected from with new + /// _actualProcessState as input, + /// - successExitState being set to (null). + /// This will lock the sate change after completion as multiple processes may be active and a state change after + /// completion may cause unpredictable operation, the state is already where it should be (manually changed), + /// - change the state after the SetupProcess() call manually. + /// + /// This is needed for non-blocking immediately new state change (not waiting for the successful execution of + /// the actual new assigned process): + /// E.g. all DB accesses need a certain time to get data, kicking off (fire and forget) the process without + /// waiting for the result, the exitSuccessState has to be set to null to avoid a state change on successfully + /// execution of the process. Instead, change the state here to go ahead with the next state. This forces a wait + /// on the state who needs the data from the "fire and forget" states, SEE next instruction how to proceed! + /// + /// + /// INSTRUCTION TO DELAY THE START OF A PROCESS: + /// -------------------------------------------- + /// Each new process execution can be delayed as it may need the result of another process which is active. + /// + /// Wait for a single process to complete: + /// - set the "waitForSingleProcess" to the process to wait for. + /// Wait for all preceding processes to complete: + /// - set the "waitForAllProcesses" to true. + /// + /// + /// + /// - Initial + /// + private void GenericStateMachine() + {// avoid repeated execution of the state machine on unchanged state + if (_stateMachineState == _lockedProcessState) + { + Thread.Sleep(ProcessTimerCycleMs >> 1); + } + else + { + try + { + // remind backup state to avoid repeated execution and side effects + _lockedProcessState = _stateMachineState; + + // signal overall process progress to GUI based on ready processes + CalcAndPushOverAllProgress(); + + // signal state change to logger + OverallProcessStateChanged(this, new ProcessStateArgs(_stateMachineState)); + + // get the actual required process from the state definition list + var process = _processStateDef?.GetProcessOfState(_stateMachineState); + + switch (_stateMachineState) + { + case ProcessState.Idle: + // This state needs an external state change like user input to go ahead + break; + + case ProcessState.DetectCordonel: + // Wait for cancellation + if (_cancellationToken.IsCancellationRequested) + { + Thread.Sleep(1000); + // Reset the cancellation request + _cancellationTokenSource?.Dispose(); + _cancellationTokenSource = new CancellationTokenSource(); + _cancellationToken = _cancellationTokenSource.Token; + } + + // Set up the counter for maximum overall process progress bar in GUI + CalcAndPushMaxOverAllProcessSteps(); + + // Detection of Cordonel has to be completed before assigning next state, so leave to automatic + // to change the state after successfully execution. The detection is the base for all others. + StartProcess(process, ProcessState.CheckNewMeter); + break; + + case ProcessState.CheckNewMeter: + // Detection of Cordonel has to be completed before assigning next state. It has to be checked if + // the meter changed to clear all collected contents of previous run. To UPDATE ALL INFORMATION after + // new meter assignment the "DetectCordonel" has to be repeated to return here "Old Meter" and then + // enter the "ConnectCordonel"! + _stateMachineState = CheckForNewMeter() ? ProcessState.DetectCordonel : ProcessState.ConnectCordonel; + break; + + case ProcessState.ConnectCordonel: + // Precondition: - The detection process has to be completed as the PcbId is needed. + // AVOID to change the process state on completion as parallel process is active! + StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion); + // Do not wait on completion as new parallel process can be started by manually state change. + _stateMachineState = ProcessState.GetSerialNumberAndRadioAddress; + break; + + case ProcessState.GetSerialNumberAndRadioAddress: + // Precondition: - The detection process has to be completed as the PcbId is needed. + // AVOID to change the process state on completion as parallel process is active! + StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion); + // Do not wait on completion as new parallel process can be started by manually state change. + _stateMachineState = ProcessState.GetProgrammingParameters; + break; + + case ProcessState.CheckOrderNumber: + // This scans the order number, it has to be executed exclusively with automatic + StartProcess(process, ProcessState.CheckSerialNumber, waitForAllProcesses: true); + break; + + case ProcessState.CheckSerialNumber: + // This scans the serial number, it has to be executed exclusively with automatic + StartProcess(process, ProcessState.CheckAttachments); + break; + + case ProcessState.RepeatFailedTests: + _stateMachineState = RepeatFailedTests(); + break; + + case ProcessState.PrintReturnReport: + _stateMachineState = ProcessState.Idle; + break; + + case ProcessState.PrintSuccessReport: + _stateMachineState = ProcessState.Idle; + break; + + case ProcessState.AbortTest: + AbortProcesses(); + _stateMachineState = ProcessState.Idle; + break; + + case ProcessState.Stop: + KillProcesses(); + _stateMachineState = ProcessState.Idle; + break; + + case ProcessState.Error: + // Common error handling routine + ProcessErrorHandler(_stateChangeRequestProcess); + // Start the error handler with its user feedback request. It has to be started + // always even if the abortion of all processes is required! The error handler + // will change the exit state based on the user input. + StartProcess(process, ProcessState.Idle, startAlways: true); + break; + + case ProcessState.StateListDelimiter: + _stateMachineState = ProcessState.Idle; + break; + + default: + IndividualStateMachine(process); + break; + } + } + catch (ThreadAbortException ex) + { + _genesisMeter?.WriteLog(ex.Message); + _stateMachineState = ProcessState.Idle; + } + catch (Exception ex) + { + _genesisMeter?.WriteLog(ex.Message); + _stateMachineState = ProcessState.Error; + } + } + }// state locked against repeated execution + #endregion --------------------------------------- State Machine ---------------------------------------------- #region ------------------------------------------ Tools ------------------------------------------------------ diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProductionProcess.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProductionProcess.cs index 741e8986..79360a99 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProductionProcess.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/BaseProductionProcess.cs @@ -292,7 +292,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses /// public void StartProcess(ProcessState? successExitState, ProcessState errorExitState = ProcessState.Error, - ProcessState breakExitState = ProcessState.AbortFinalTest) + ProcessState breakExitState = ProcessState.AbortTest) { if (Meter == null) { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/Enum/ProcessState.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/Enum/ProcessState.cs index fd68e028..b15cb83e 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/Enum/ProcessState.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/Enum/ProcessState.cs @@ -19,17 +19,17 @@ /// Error, /// - /// Abort final test execution + /// Abort test execution /// - AbortFinalTest, + AbortTest, /// - /// Repeat the entire final test + /// Repeat the entire test /// RepeatFailedTests, /// /// Final test failed /// - FinalTestFailed, + TestFailed, /// /// User stopped process /// diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs index 72993b35..bc596ccf 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/CheckProductionState.cs @@ -15,8 +15,8 @@ using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Logic.ProductionOrderCore.OrderData; using Xylem.Common.Logic.ProductionOrderCore.TestResults; using Xylem.Common.Production.ProductionUiCordonel.Model; -using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses; using Xylem.Common.Production.ProductionUiCordonel.Properties; namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessController.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessController.cs deleted file mode 100644 index 58041c78..00000000 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessController.cs +++ /dev/null @@ -1,314 +0,0 @@ -using System; -using System.Threading; -using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; -using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs; - -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses -{ - /// - /// Preparing the Cordonel for shipping: - /// - Setup device with standard parameters covered by the VAKO or customer specific CSD, - /// - If radio is installed: radio test, - /// - Requiring radio key from LuDB, - /// - Requiring 7 passwords for the Cordonel access levels, - /// - Building the password file (Level 3 is the modified skeleton key), - /// - Store all configurations, - /// - Reboot the Cordonel to load all settings from FLASH to RAM, - /// - Configuration check of all parameters defined by VAKO and CSD. - /// - public sealed class EolProcessController : BaseProcessController, IProcessController - { - #region ------------------------------------------ Variables -------------------------------------------------- - // - #endregion --------------------------------------- Variables -------------------------------------------------- - #region ------------------------------------------ Class ------------------------------------------------------ - - /// - /// Ctor - /// - /// physical slot for this meter - /// - /// - Initial - /// - public EolProcessController(Int32 slot) : base(slot) - { - } - - #endregion --------------------------------------- Class ------------------------------------------------------ - #region ------------------------------------------ Events ----------------------------------------------------- - // - #endregion --------------------------------------- Events ----------------------------------------------------- - #region ------------------------------------------ State Machine ---------------------------------------------- - /// - /// State machine of FinalProcessController which serves as preparation for SHIPPING named EOL (End-Of-Line). - /// - /// - /// INSTRUCTION FOR NORMAL USAGE: - /// ----------------------------- - /// Call the SetupProcess() with the - /// - new process automatically collected from with new - /// _actualProcessState as input, - /// - successExitState set to the next required state after successfully execution. - /// That's it! The normal state change has always only one production process active and waits for completion - /// before changing to a new state and therefore a new production process. - /// - /// If a special state is needed on errorExitState or breakExitState these can be assigned. Otherwise, the - /// errorExitState is linked to the error state, the breakExitState to the stop state. - /// - /// - /// INSTRUCTION FOR NON-BLOCKING MULTIPLE PROCESSES SIMULTANEOUSLY ACTIVITIES: - /// -------------------------------------------------------------------------- - /// Sometimes production processes may be able to be executed simultaneously as they are independent of each - /// other. One example is a database access for data collection from different tables. - /// - /// Call the SetupProcess with the - /// - new process automatically collected from with new - /// _actualProcessState as input, - /// - successExitState being set to (null). - /// This will lock the sate change after completion as multiple processes may be active and a state change after - /// completion may cause unpredictable operation, the state is already where it should be (manually changed), - /// - change the state after the SetupProcess() call manually. - /// - /// This is needed for non-blocking immediately new state change (not waiting for the successful execution of - /// the actual new assigned process): - /// E.g. all DB accesses need a certain time to get data, kicking off (fire and forget) the process without - /// waiting for the result, the exitSuccessState has to be set to null to avoid a state change on successfully - /// execution of the process. Instead, change the state here to go ahead with the next state. This forces a wait - /// on the state who needs the data from the "fire and forget" states, SEE next instruction how to proceed! - /// - /// - /// INSTRUCTION TO DELAY THE START OF A PROCESS: - /// -------------------------------------------- - /// Each new process execution can be delayed as it may need the result of another process which is active. - /// - /// Wait for a single process to complete: - /// - set the "waitForSingleProcess" to the process to wait for. - /// Wait for all preceding processes to complete: - /// - set the "waitForAllProcesses" to true. - /// - /// - /// - /// - Initial - /// - public override void StateMachine() - { - // avoid repeated execution of the state machine on unchanged state - if (_stateMachineState == _lockedProcessState) - { - Thread.Sleep(ProcessTimerCycleMs >> 1); - } - else - { - try - { - // remind backup state to avoid repeated execution and side effects - _lockedProcessState = _stateMachineState; - - // signal overall process progress to GUI based on ready processes - CalcAndPushOverAllProgress(); - - // signal state change to logger - OverallProcessStateChanged(this, new ProcessStateArgs(_stateMachineState)); - - // get the actual required process from the state definition list - var process = _processStateDef?.GetProcessOfState(_stateMachineState); - - switch (_stateMachineState) - { - case ProcessState.Idle: - // This state needs an external state change like user input to go ahead - break; - - case ProcessState.DetectCordonel: - // Wait for cancellation - if (_cancellationToken.IsCancellationRequested) - { - Thread.Sleep(1000); - // Reset the cancellation request - _cancellationTokenSource?.Dispose(); - _cancellationTokenSource = new CancellationTokenSource(); - _cancellationToken = _cancellationTokenSource.Token; - } - - // Set up the counter for maximum overall process progress bar in GUI - CalcAndPushMaxOverAllProcessSteps(); - - // Detection of Cordonel has to be completed before assigning next state, so leave to automatic - // to change the state after successfully execution. The detection is the base for all others. - StartProcess(process, ProcessState.CheckNewMeter); - break; - - case ProcessState.CheckNewMeter: - // Detection of Cordonel has to be completed before assigning next state. It has to be checked if - // the meter changed to clear all collected contents of previous run. To UPDATE ALL INFORMATION after - // new meter assignment the "DetectCordonel" has to be repeated to return here "Old Meter" and then - // enter the "ConnectCordonel"! - _stateMachineState = CheckForNewMeter() ? ProcessState.DetectCordonel : ProcessState.ConnectCordonel; - break; - - case ProcessState.ConnectCordonel: - // Precondition: - The detection process has to be completed as the PcbId is needed. - // AVOID to change the process state on completion as parallel process is active! - StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion); - // Do not wait on completion as new parallel process can be started by manually state change. - _stateMachineState = ProcessState.GetSerialNumberAndRadioAddress; - break; - - case ProcessState.GetSerialNumberAndRadioAddress: - // Precondition: - The detection process has to be completed as the PcbId is needed. - // AVOID to change the process state on completion as parallel process is active! - StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion); - // Do not wait on completion as new parallel process can be started by manually state change. - _stateMachineState = ProcessState.GetProgrammingParameters; - break; - - case ProcessState.GetProgrammingParameters: - // Precondition: - The connection process has to be completed as a readout of some register - // values from the Cordonel are needed to check the update capability: - // - Wait on completed connection process before starting this process. - // AVOID to change the process state on completion as parallel process is active! - StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion, - waitForSingleProcess: _processStateDef?.GetProcessOfState(ProcessState.ConnectCordonel)); - // Do not wait on completion as new parallel process can be started by manually state change. - _stateMachineState = ProcessState.CheckProductionState; - break; - - case ProcessState.CheckProductionState: - // Precondition: - The connection process has to be completed as a readout of some register - // values from the Cordonel are needed to check the update capability: - // - Wait on completed connection process before starting this process. - // AVOID to change the process state on completion as parallel process is active! - StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion, - waitForSingleProcess: _processStateDef?.GetProcessOfState(ProcessState.ConnectCordonel)); - // Do not wait on completion as new parallel process can be started by manually state change. - _stateMachineState = ProcessState.ProcessPasswordFile; - break; - - case ProcessState.ProcessPasswordFile: - // Precondition: - The connection process has to be completed as a password change in the DB - // will take place: Skeleton to Password Level 8. Not waiting for completion may cause side - // effects on login. Wait for all processes to complete. - // Leave state switch to automatic to avoid side effects on incomplete updated DB for next - // steps. - StartProcess(process, ProcessState.ExecFinalParametrization, waitForAllProcesses: true); - break; - - case ProcessState.ExecFinalParametrization: - // This writes all setups to the device, it has to be executed exclusively with automatic - StartProcess(process, ProcessState.ExecStoreConfiguration); - break; - - case ProcessState.ExecStoreConfiguration: - // Precondition: - The final parametrization has to be finished as this shall be stored - // to non-volatile memory and checked if remaining valid after the reboot. - // Store configuration has to be executed exclusively with automatic - StartProcess(process, ProcessState.RebootCordonel); - break; - - case ProcessState.RebootCordonel: - // Precondition: - The store configuration has to be executed to safe all settings - // to non-volatile memory and checked if remaining valid after the reboot. - // Reboot has to be executed exclusively with automatic - StartProcess(process, ProcessState.CheckFinalParametrization); - break; - - case ProcessState.CheckFinalParametrization: - // Precondition: - The reboot process including the store all configurations has to be - // completed. - // Check final configuration has to be executed exclusively with automatic - StartProcess(process, ProcessState.CheckRadio); - break; - - case ProcessState.CheckRadio: - // Precondition: - The final parametrization, reboot process including the store all - // configurations and the check of all setups survived the reboot have to be completed. - // Radio signal level check, skipped on NA region or if skipping is required by special - // approval - StartProcess(process, ProcessState.CheckOrderNumber); - break; - - case ProcessState.CheckOrderNumber: - // This scans the order number, it has to be executed exclusively with automatic - StartProcess(process, ProcessState.CheckSerialNumber, waitForAllProcesses: true); - break; - - case ProcessState.CheckSerialNumber: - // This scans the serial number, it has to be executed exclusively with automatic - StartProcess(process, ProcessState.CheckAttachments); - break; - - case ProcessState.CheckAttachments: - // Precondition: - All checks have to be executed with positive result - StartProcess(process, ProcessState.ExecVisualInspection); - break; - - case ProcessState.ExecVisualInspection: - // Precondition: - All checks have to be executed with positive result - StartProcess(process, ProcessState.PrepareShippingMode); - break; - - case ProcessState.PrepareShippingMode: - // Precondition: - All checks have to be executed with positive result - StartProcess(process, ProcessState.ReadyForShipping); - break; - - case ProcessState.ReadyForShipping: - _stateMachineState = ProcessState.Idle; - break; - - case ProcessState.RepeatFailedTests: - _stateMachineState = RepeatFailedTests(); - break; - - case ProcessState.PrintReturnReport: - _stateMachineState = ProcessState.Idle; - break; - - case ProcessState.PrintSuccessReport: - _stateMachineState = ProcessState.Idle; - break; - - case ProcessState.AbortFinalTest: - AbortProcesses(); - _stateMachineState = ProcessState.Idle; - break; - - case ProcessState.Stop: - KillProcesses(); - _stateMachineState = ProcessState.Idle; - break; - - case ProcessState.Error: - // Common error handling routine - ProcessErrorHandler(_stateChangeRequestProcess); - // Start the error handler with its user feedback request. It has to be started - // always even if the abortion of all processes is required! The error handler - // will change the exit state based on the user input. - StartProcess(process, ProcessState.Idle, startAlways: true); - break; - - case ProcessState.StateListDelimiter: - default: - _stateMachineState = ProcessState.Idle; - break; - }// - } - catch (ThreadAbortException ex) - { - _genesisMeter?.WriteLog(ex.Message); - _stateMachineState = ProcessState.Idle; - } - catch (Exception ex) - { - _genesisMeter?.WriteLog(ex.Message); - _stateMachineState = ProcessState.Error; - } - } - }// state locked against repeated execution - - #endregion --------------------------------------- State Machine ---------------------------------------------- - #region ------------------------------------------ Tools ------------------------------------------------------ - // - #endregion --------------------------------------- Tools ------------------------------------------------------ - } -} diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStates.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStates.cs index b7c8b4c9..5652ecf7 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStates.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolProcessStates.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; -using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses; using Xylem.Common.Production.ProductionUiCordonel.Properties; namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses @@ -60,7 +60,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr new ProcessStateStruct( null, - ProcessState.AbortFinalTest, + ProcessState.AbortTest, Resources.StrStateSkipping, false), @@ -72,7 +72,7 @@ namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolPr new ProcessStateStruct( null, - ProcessState.FinalTestFailed, + ProcessState.TestFailed, Resources.StrStateFinalTestFailed, false), diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolStateMachine.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolStateMachine.cs new file mode 100644 index 00000000..62c3fcd1 --- /dev/null +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/EolStateMachine.cs @@ -0,0 +1,148 @@ +using System; +using System.Threading; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs; + +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses +{ + /// + /// Preparing the Cordonel for shipping: + /// - Setup device with standard parameters covered by the VAKO or customer specific CSD, + /// - If radio is installed: radio test, + /// - Requiring radio key from LuDB, + /// - Requiring 7 passwords for the Cordonel access levels, + /// - Building the password file (Level 3 is the modified skeleton key), + /// - Store all configurations, + /// - Reboot the Cordonel to load all settings from FLASH to RAM, + /// - Configuration check of all parameters defined by VAKO and CSD. + /// + public sealed class EolStateMachine : BaseProcessController, IProcessController + { + #region ------------------------------------------ Variables -------------------------------------------------- + // + #endregion --------------------------------------- Variables -------------------------------------------------- + #region ------------------------------------------ Class ------------------------------------------------------ + + /// + /// Ctor + /// + /// physical slot for this meter + /// + /// - Initial + /// + public EolStateMachine(Int32 slot) : base(slot) + { + } + + #endregion --------------------------------------- Class ------------------------------------------------------ + #region ------------------------------------------ Events ----------------------------------------------------- + // + #endregion --------------------------------------- Events ----------------------------------------------------- + #region ------------------------------------------ State Machine ---------------------------------------------- + /// + /// + /// State machine of FinalProcessController which serves as preparation for SHIPPING named EOL (End-Of-Line). + /// + /// + /// - Initial + /// + public override void IndividualStateMachine(IProductionProcess process) + { + switch (_stateMachineState) + { + case ProcessState.GetProgrammingParameters: + // Precondition: - The connection process has to be completed as a readout of some register + // values from the Cordonel are needed to check the update capability: + // - Wait on completed connection process before starting this process. + // AVOID to change the process state on completion as parallel process is active! + StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion, + waitForSingleProcess: _processStateDef?.GetProcessOfState(ProcessState.ConnectCordonel)); + // Do not wait on completion as new parallel process can be started by manually state change. + _stateMachineState = ProcessState.CheckProductionState; + break; + + case ProcessState.CheckProductionState: + // Precondition: - The connection process has to be completed as a readout of some register + // values from the Cordonel are needed to check the update capability: + // - Wait on completed connection process before starting this process. + // AVOID to change the process state on completion as parallel process is active! + StartProcess(process, BaseProductionProcess.DoNotChangeStateAfterCompletion, + waitForSingleProcess: _processStateDef?.GetProcessOfState(ProcessState.ConnectCordonel)); + // Do not wait on completion as new parallel process can be started by manually state change. + _stateMachineState = ProcessState.ProcessPasswordFile; + break; + + case ProcessState.ProcessPasswordFile: + // Precondition: - The connection process has to be completed as a password change in the DB + // will take place: Skeleton to Password Level 8. Not waiting for completion may cause side + // effects on login. Wait for all processes to complete. + // Leave state switch to automatic to avoid side effects on incomplete updated DB for next + // steps. + StartProcess(process, ProcessState.ExecFinalParametrization, waitForAllProcesses: true); + break; + + case ProcessState.ExecFinalParametrization: + // This writes all setups to the device, it has to be executed exclusively with automatic + StartProcess(process, ProcessState.ExecStoreConfiguration); + break; + + case ProcessState.ExecStoreConfiguration: + // Precondition: - The final parametrization has to be finished as this shall be stored + // to non-volatile memory and checked if remaining valid after the reboot. + // Store configuration has to be executed exclusively with automatic + StartProcess(process, ProcessState.RebootCordonel); + break; + + case ProcessState.RebootCordonel: + // Precondition: - The store configuration has to be executed to safe all settings + // to non-volatile memory and checked if remaining valid after the reboot. + // Reboot has to be executed exclusively with automatic + StartProcess(process, ProcessState.CheckFinalParametrization); + break; + + case ProcessState.CheckFinalParametrization: + // Precondition: - The reboot process including the store all configurations has to be + // completed. + // Check final configuration has to be executed exclusively with automatic + StartProcess(process, ProcessState.CheckRadio); + break; + + case ProcessState.CheckRadio: + // Precondition: - The final parametrization, reboot process including the store all + // configurations and the check of all setups survived the reboot have to be completed. + // Radio signal level check, skipped on NA region or if skipping is required by special + // approval + StartProcess(process, ProcessState.CheckOrderNumber); + break; + + case ProcessState.CheckAttachments: + // Precondition: - All checks have to be executed with positive result + StartProcess(process, ProcessState.ExecVisualInspection); + break; + + case ProcessState.ExecVisualInspection: + // Precondition: - All checks have to be executed with positive result + StartProcess(process, ProcessState.PrepareShippingMode); + break; + + case ProcessState.PrepareShippingMode: + // Precondition: - All checks have to be executed with positive result + StartProcess(process, ProcessState.ReadyForShipping); + break; + + case ProcessState.ReadyForShipping: + _stateMachineState = ProcessState.Idle; + break; + + default: + _stateMachineState = ProcessState.Idle; + break; + } + } + + #endregion --------------------------------------- State Machine ---------------------------------------------- + #region ------------------------------------------ Tools ------------------------------------------------------ + // + #endregion --------------------------------------- Tools ------------------------------------------------------ + } +} diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/GetFinalParametrization.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/GetFinalParametrization.cs index 2a322f9a..aa67ea14 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/GetFinalParametrization.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/EolProcesses/GetFinalParametrization.cs @@ -7,7 +7,7 @@ using Xylem.Common.CommonCore.Consts; using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore; using Xylem.Common.Hardware.WaterMeter.Genesis.Registers; using Xylem.Common.Logic.SoftwareAccessHelper; -using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses; +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses; using Xylem.Common.Production.ProductionUiCordonel.Properties; namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/CheckOrderNumber.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckOrderNumber.cs similarity index 99% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/CheckOrderNumber.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckOrderNumber.cs index 6eb900f3..3b4a7056 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/CheckOrderNumber.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckOrderNumber.cs @@ -4,7 +4,7 @@ using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; using Xylem.Common.Production.ProductionUiCordonel.UserControls; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses { public class CheckOrderNumber : BaseProductionProcess { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/CheckSerialNumber.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckSerialNumber.cs similarity index 99% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/CheckSerialNumber.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckSerialNumber.cs index 586e1f5b..ba488770 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/CheckSerialNumber.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/CheckSerialNumber.cs @@ -4,7 +4,7 @@ using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; using Xylem.Common.Production.ProductionUiCordonel.UserControls; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses { public class CheckSerialNumber : BaseProductionProcess { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/ConnectCordonel.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/ConnectCordonel.cs similarity index 98% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/ConnectCordonel.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/ConnectCordonel.cs index a0fac18a..da46434a 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/ConnectCordonel.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/ConnectCordonel.cs @@ -3,7 +3,7 @@ using Xylem.Common.CommonCore.Consts; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses { public class ConnectCordonel : BaseProductionProcess { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/DetectCordonel.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/DetectCordonel.cs similarity index 98% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/DetectCordonel.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/DetectCordonel.cs index fef61032..0c2d9993 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/DetectCordonel.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/DetectCordonel.cs @@ -3,7 +3,7 @@ using Xylem.Common.CommonCore.Consts; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses { /// /// Production process detects the serial number of the Cordonel. diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/ErrorHandler.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/ErrorHandler.cs similarity index 99% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/ErrorHandler.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/ErrorHandler.cs index e333b9bd..78f5a3eb 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/ErrorHandler.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/ErrorHandler.cs @@ -5,7 +5,7 @@ using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; using Xylem.Common.Production.ProductionUiCordonel.UserControls; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses { public class ErrorHandler : BaseProductionProcess { diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/GetSerialNumberAndRadioAddress.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/GetSerialNumberAndRadioAddress.cs similarity index 99% rename from Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/GetSerialNumberAndRadioAddress.cs rename to Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/GetSerialNumberAndRadioAddress.cs index 562d993e..a912e5a7 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/CommonProcesses/GetSerialNumberAndRadioAddress.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/GenericProcesses/GetSerialNumberAndRadioAddress.cs @@ -8,7 +8,7 @@ using Xylem.Common.Logic.SoftwareAccessHelper; using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; using Xylem.Common.Production.ProductionUiCordonel.Properties; -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.CommonProcesses +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.GenericProcesses { /// /// Request the serial number and radio address from DB. diff --git a/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessController.cs b/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessController.cs index 26615686..5a88c1ae 100644 --- a/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessController.cs +++ b/Common/Production/ProductionUiCordonel/ProductionProcesses/IProcessController.cs @@ -1,58 +1,12 @@ -namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses +using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum; +namespace Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses { public interface IProcessController { /// - /// State machine of ProcessController which serves as template for all production processes. - /// - /// - /// INSTRUCTION FOR NORMAL USAGE: - /// ----------------------------- - /// Call the SetupProcess() with the - /// - new process automatically collected from with new - /// _actualProcessState as input, - /// - successExitState set to the next required state after successfully execution. - /// That's it! The normal state change has always only one production process active and waits for completion - /// before changing to a new state and therefore a new production process. - /// - /// If a special state is needed on errorExitState or breakExitState these can be assigned. Otherwise, the - /// errorExitState is linked to the error state, the breakExitState to the stop state. - /// - /// - /// INSTRUCTION FOR NON-BLOCKING MULTIPLE PROCESSES SIMULTANEOUSLY ACTIVITIES: - /// -------------------------------------------------------------------------- - /// Sometimes production processes may be able to be executed simultaneously as they are independent of each - /// other. One example is a database access for data collection from different tables. - /// - /// Call the SetupProcess with the - /// - new process automatically collected from with new - /// _actualProcessState as input, - /// - successExitState being set to (null). - /// This will lock the sate change after completion as multiple processes may be active and a state change after - /// completion may cause unpredictable operation, the state is already where it should be (manually changed), - /// - change the state after the SetupProcess() call manually. - /// - /// This is needed for non-blocking immediately new state change (not waiting for the successful execution of - /// the actual new assigned process): - /// E.g. all DB accesses need a certain time to get data, kicking off (fire and forget) the process without - /// waiting for the result, the exitSuccessState has to be set to null to avoid a state change on successfully - /// execution of the process. Instead, change the state here to go ahead with the next state. This forces a wait - /// on the state who needs the data from the "fire and forget" states, SEE next instruction how to proceed! - /// - /// - /// INSTRUCTION TO DELAY THE START OF A PROCESS: - /// -------------------------------------------- - /// Each new process execution can be delayed as it may need the result of another process which is active. - /// - /// Wait for a single process to complete: - /// - set the "waitForSingleProcess" to the process to wait for. - /// Wait for all preceding processes to complete: - /// - set the "waitForAllProcesses" to true. - /// + /// Individual states to fill the state machine. + /// ATTENTION: All states have to be part of the /// - /// - /// - Initial - /// - void StateMachine(); + void IndividualStateMachine(IProductionProcess process); } } diff --git a/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj b/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj index 767a4554..945346a8 100644 --- a/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj +++ b/Common/Production/ProductionUiCordonel/ProductionUiCordonel.csproj @@ -289,10 +289,10 @@ - + - - + + @@ -300,7 +300,7 @@ - + @@ -319,15 +319,15 @@ MultiModeChild.xaml - - + + - +