/// <summary> /// The given loc has waited at it's destination. /// Let's assign a new route. /// </summary> /// <returns>The timespan before this method wants to be called again.</returns> private TimeSpan OnWaitingForDestinationGroupMinimum(ILocState loc, int generationDelta) { // Check state var state = loc.AutomaticState.Actual; if (state != AutoLocState.WaitingForDestinationGroupMinimum) { log.Warn("Loc {0} in valid state ({1}) at destination timeout.", loc, loc.AutomaticState); return(TimeSpan.MaxValue); } // Log state log.Trace("OnWaitingForDestinationGroupMinimum {0}", loc); // Do we still control this loc? if (!ShouldControlAutomatically(loc)) { RemoveLocFromAutomaticControl(loc); return(TimeSpan.MaxValue); } // Timeout reached? if (loc.CanLeaveCurrentBlock() || overrideLeaveCurrentBlock(generationDelta)) { // Yes, let's assign a new route loc.AutomaticState.Actual = AutoLocState.AssignRoute; return(TimeSpan.Zero); } // Nothing changed return(TimeSpan.MaxValue); }
/// <summary> /// The given loc has waited at it's destination. /// Let's assign a new route. /// </summary> /// <returns>The timespan before this method wants to be called again.</returns> private TimeSpan OnWaitingForDestinationTimeout(ILocState loc) { // Check state var state = loc.AutomaticState.Actual; if (state != AutoLocState.WaitingForDestinationTimeout) { log.Warn("Loc {0} in valid state ({1}) at destination timeout.", loc, loc.AutomaticState); return(TimeSpan.MaxValue); } // Log state log.Trace("OnWaitingForDestinationTimeout {0}", loc); // Do we still control this loc? if (!ShouldControlAutomatically(loc)) { RemoveLocFromAutomaticControl(loc); return(TimeSpan.MaxValue); } // Timeout reached? var startNextRouteTime = loc.StartNextRouteTime.Actual; var now = DateTime.Now; if (now >= startNextRouteTime) { // Check the block group, see if we can leave if (loc.CanLeaveCurrentBlock()) { // Yes, let's assign a new route loc.AutomaticState.Actual = AutoLocState.AssignRoute; return(TimeSpan.Zero); } else { // No we cannot leave yet loc.AutomaticState.Actual = AutoLocState.WaitingForDestinationGroupMinimum; return(TimeSpan.MaxValue); } } // Nothing changed return(startNextRouteTime.Subtract(now)); }
/// <summary> /// Try to assign a route to the given loc. /// </summary> /// <returns>The timespan before this method wants to be called again.</returns> private TimeSpan OnAssignRoute(ILocState loc, int generationDelta, ref int locsWithNoRoute) { // Check state var state = loc.AutomaticState.Actual; if (state != AutoLocState.AssignRoute) { log.Warn("Cannot assign route to loc {0} in {1} state.", loc, loc.AutomaticState); return(TimeSpan.MaxValue); } // Log state log.Trace("OnAssignRoute {0}", loc); // Does the locs still wants to be controlled? if (!ShouldControlAutomatically(loc)) { RemoveLocFromAutomaticControl(loc); return(TimeSpan.MaxValue); } // Look for a free route from the current destination var block = loc.CurrentBlock.Actual; if (block == null) { // Oops, no current block, we cannot control this loc RemoveLocFromAutomaticControl(loc); return(TimeSpan.MaxValue); } // Is a reversing block on a block where it must un-reverse? if (loc.Reversing.Actual && block.ChangeDirectionReversingLocs) { // Change direction and clear the reversing flag loc.CurrentBlockEnterSide.Actual = loc.CurrentBlockEnterSide.Actual.Invert(); loc.Reversing.Actual = false; loc.Direction.Requested = loc.Direction.Actual.Invert(); loc.AutomaticState.Actual = AutoLocState.ReversingWaitingForDirectionChange; loc.PossibleDeadlock.Actual = false; return(TimeSpan.Zero); } // Select next route var route = loc.NextRoute.Actual; if (route == null) { // No next route was set if ((loc.Speed.Requested == 0) && (!loc.CanLeaveCurrentBlock()) && (!overrideLeaveCurrentBlock(generationDelta))) { // We're not running and we're not allowed to leave the current block loc.AutomaticState.Actual = AutoLocState.WaitingForDestinationGroupMinimum; loc.PossibleDeadlock.Actual = false; return(TimeSpan.FromMinutes(1)); } // Choose a next route now route = ChooseRoute(loc, block, loc.CurrentBlockEnterSide.Actual.Invert(), false, generationDelta); } if (route == null) { // No possible routes right now, try again locsWithNoRoute++; DateTime since; if (!locHasNoRouteSince.TryGetValue(loc, out since)) { locHasNoRouteSince[loc] = DateTime.Now; } else { loc.PossibleDeadlock.Actual = (DateTime.Now.Subtract(since).TotalSeconds > 30); } return(TimeSpan.FromSeconds(5)); } else { locHasNoRouteSince.Remove(loc); loc.PossibleDeadlock.Actual = false; } // Lock the route route.Lock(loc); // Setup waiting after block (do this before assigning the route) if (route.To.WaitPermissions.Evaluate(loc)) { // Waiting allowed, gamble for it. var waitProbability = route.To.WaitProbability; loc.WaitAfterCurrentRoute.Actual = ThreadStatics.Random.Gamble(waitProbability); } else { // Waiting not allowed. loc.WaitAfterCurrentRoute.Actual = false; } // Assign the route loc.CurrentRoute.Actual = route.CreateStateForLoc(loc); // Clear next route loc.NextRoute.Actual = null; // Should we change direction? var enteredSide = loc.CurrentBlockEnterSide.Actual; var leavingSide = route.FromBlockSide; if (enteredSide == leavingSide) { // Reverse direction loc.Direction.Requested = loc.Direction.Actual.Invert(); // Are we reversing now? if (loc.ChangeDirection == ChangeDirection.Avoid) { loc.Reversing.Actual = !loc.Reversing.Actual; } // When reversing, check the state of the target block if (loc.Reversing.Actual && route.To.ChangeDirectionReversingLocs) { // We must stop at the target block loc.WaitAfterCurrentRoute.Actual = true; } } // Change state loc.AutomaticState.Actual = AutoLocState.WaitingForAssignedRouteReady; // Prepare the route? route.Prepare(); // We're done return(TimeSpan.Zero); }