public static AutoModeTaskBase Create(NextRouteInformation route, AutoMode ctx) { var instance = new AutoModeTaskBase { Ctx = ctx, Route = route }; return(instance); }
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); }