Esempio n. 1
0
        public static AutoModeTaskBase Create(NextRouteInformation route, AutoMode ctx)
        {
            var instance = new AutoModeTaskBase
            {
                Ctx   = ctx,
                Route = route
            };

            return(instance);
        }
Esempio n. 2
0
        public async override Task Run()
        {
            #region prepare data for autoMode task

            var dpS88 = Route.DataProviderS88;

            //var currentDirection = Route.Locomotive.Direction;
            var currentSpeed = Route.Locomotive.Speedstep;
            var maxSpeed     = Route.Locomotive.GetNumberOfSpeedsteps();
            var speedCurve   = Route.LocomotivesData?.SpeedCurve;

            var targetSpeed = Locomotive.GetFallbackSpeed(maxSpeed);
            if (speedCurve != null)
            {
                targetSpeed = speedCurve.MaxSpeed;
            }
            else
            {
                if (Route.LocomotivesData != null)
                {
                    targetSpeed = Route.LocomotivesData.GetLevel(MaxSpeedLevelAutoMode).Value;
                }

                if (targetSpeed == 0)
                {
                    targetSpeed = Locomotive.GetFallbackSpeed(maxSpeed);
                }
            }

            #endregion

            await Task.Run(async() =>
            {
                SendDebugMessage($"Start: {Route.Route.Name}");

                //
                // NOTE reset additional locked blocks
                //
                UnlockAdditionalBlocksFor(Route.FromBlock);
                Ctx?.SaveFeedbacksAndPromote();

                //
                // NOTE apply all accessory states before start of locomotive traveling
                //
                SetAccessories();

                if (IsCanceled())
                {
                    return;
                }

                //
                // NOTE start train, if the fbEnter is reached before the train got its full speed, cancel the speed-up
                //
                const int maxSecondsForAcceleration = 10;
                var fbEnterAlreadyReached           = false;
                if (speedCurve != null)
                {
                    SendDebugMessage($"Using speed curve to accelerate {Route.Locomotive.Caption}.");

                    await AccelerateLocomotiveCurve(currentSpeed, Route.Locomotive, speedCurve, hasToBeCanceled: () =>
                    {
                        fbEnterAlreadyReached = IsFbReached("FbEnter", Route.FbEnter, dpS88, out var hasError);
                        // TODO handle hasError (e.g. cancel route)
                        return(fbEnterAlreadyReached);
                    });
                }
                else
                {
                    await AccelerateLocomotive(currentSpeed, targetSpeed, Route.Locomotive, maxSecondsForAcceleration, () =>
                    {
                        fbEnterAlreadyReached = IsFbReached("FbEnter", Route.FbEnter, dpS88, out var hasError);
                        // TODO handle hasError (e.g. cancel route)
                        return(fbEnterAlreadyReached);
                    });
                }

                if (IsCanceled())
                {
                    return;
                }

                //
                // NOTE wait for entering the fbEnter feedback
                //
                if (!fbEnterAlreadyReached)
                {
                    await WaitForFb("FbEnter", Route.FbEnter, dpS88);
                }

                if (IsCanceled())
                {
                    return;
                }

                //
                // NOTE start measurement how long it takes to reach fbIn feedback
                //
                var startDt = DateTime.Now;

                //
                // NOTE trigger Ui update to visualize entering destination
                //
                Route.OccBlock.FinalEntered = true;
                Ctx?.SaveOccAndPromote();

                if (IsCanceled())
                {
                    return;
                }

                //
                // NOTE decelerate the train
                //
                var durationSeconds = 10.0;
                if (Ctx?._metadataLock != null)
                {
                    lock (Ctx._metadataLock)
                    {
                        durationSeconds = Ctx._metadata.LocomotivesDurationData.GetAverageDecelerationSeconds(
                            Route.LocomotiveObjectId,
                            Route.TargetBlock.identifier);
                    }
                }

                var fbInAlreadyReached = false;
                if (speedCurve != null)
                {
                    SendDebugMessage($"Using speed curve to decelerate {Route.Locomotive.Caption}.");

                    await DecelerateLocomotiveCurve(Route.Locomotive, speedCurve, maxSeconds: (int)durationSeconds, hasToBeCanceled: () =>
                    {
                        fbInAlreadyReached = IsFbReached("FbIn", Route.FbIn, dpS88, out var hasError);
                        // TODO handle hasError (e.g. cancel route)
                        return(fbInAlreadyReached);
                    });
                }
                else
                {
                    SendDebugMessage($"Using linear deceleration for {Route.Locomotive.Caption}.");

                    await DecelerateLocomotive(Route.Locomotive, maxSecsToStop: (int)durationSeconds, hasToBeCanceled: () =>
                    {
                        fbInAlreadyReached = IsFbReached("FbIn", Route.FbIn, dpS88, out var hasError);
                        // TODO handle hasError (e.g. cancel route)
                        return(fbInAlreadyReached);
                    });
                }

                if (IsCanceled())
                {
                    return;
                }

                //
                // NOTE wait for entering the fbIn feedback
                //
                if (!fbInAlreadyReached)
                {
                    await WaitForFb("FbIn", Route.FbIn, dpS88);
                }

                var stopDt = DateTime.Now;
                var delta  = stopDt - startDt;
                SendDebugMessage($"{delta.TotalSeconds} seconds between 'enter' and 'in'.");

                if (IsCanceled())
                {
                    return;
                }

                //
                // save duration between FB-enter and FB-in
                //
                if (Ctx?._metadataLock != null)
                {
                    lock (Ctx._metadataLock)
                    {
                        if (Ctx?._metadata != null)
                        {
                            Ctx?._metadata.LocomotivesDurationData.AddDecelerateDuration(
                                Route.LocomotiveObjectId,
                                Route.TargetBlock.identifier,
                                startDt,
                                stopDt);

                            Ctx?._metadata.Save(Metadata.SaveModelType.LocomotivesDurationsData);
                        }
                    }
                }

                //
                // NOTE stop the locomotive in any case when fbIn is reached
                //
                Ctx?.GetClientHandler()?.LocomotiveChangeSpeedstep(Route.Locomotive, 0);

                //
                // NOTE check if the reached block has any additional blocks to lock
                //
                LockAdditionalBlocksFor(Route.TargetBlock);
                Ctx?.SaveFeedbacksAndPromote();

                //
                // NOTE reset the current OCC information and set the final block as new from block
                // NOTE reset the recent route, it is not occupied anymore
                // !! the order is crucial !!
                //
                var finalBlock = Route.OccBlock.FinalBlock;
                Ctx?.ResetRouteFor(Route.LocomotiveObjectId);
                Route.OccBlock.FromBlock   = finalBlock;
                Route.OccBlock.ReachedTime = DateTime.Now;
                if (Ctx != null)
                {
                    Route.OccBlock.SecondsToWait = Ctx.GetSecondsToWait();
                }
                else
                {
                    Route.OccBlock.SecondsToWait = AutoMode.GetSecondsToWaitFallback();
                }
                Ctx?.SaveOccAndPromote();

                if (IsCanceled())
                {
                    return;
                }

                //
                // NOTE set entering side for the locomotive
                //
                if (Route.TargetBlock.side == SideMarker.Plus)
                {
                    Route.LocomotivesData.EnterBlockSide = "'+' Side";
                }
                else if (Route.TargetBlock.side == SideMarker.Minus)
                {
                    Route.LocomotivesData.EnterBlockSide = "'-' Side";
                }
                else
                {
                    Route.LocomotivesData.EnterBlockSide = string.Empty;
                }
                Ctx?.SaveLocomotivesAndPromote();

                if (IsCanceled())
                {
                    return;
                }

                //
                // NOTE leave the task
                //
                SendDebugMessage($"Finished: {Route.Route.Name}");

                IsFinished = true;

                TriggerFinished();
            }, CancelSource.Token);
        }