From fa6235cfb2d112800a9ccf381ed8661d2af276f3 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Mon, 23 Dec 2024 15:14:28 +0100 Subject: [PATCH] ATC Dimetronic: runback/rollforward detection --- src/Devices/AtcDimetronic.cs | 58 +++++++++++++++++++++++++++++++++-- src/Managers/ConfigManager.cs | 18 +++++++++++ src/Train/Train.cs | 2 +- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/Devices/AtcDimetronic.cs b/src/Devices/AtcDimetronic.cs index fbf2f16..f7cf37d 100644 --- a/src/Devices/AtcDimetronic.cs +++ b/src/Devices/AtcDimetronic.cs @@ -54,12 +54,27 @@ namespace OpenbveFcmbTrainPlugin /// The current position of the train. private double TrainLocation; + /// The position of the train used to detect runback. + private double RunbackLocation; + + /// The position of the train used to detect rollforward. + private double RollforwardLocation; + + /// Whether rollforward should be detected or not. + private bool RollforwardTrigger; + /// The length of the train. private readonly double TrainLength; /// The maximum speed in YARD mode. private readonly Speed YardMaximumSpeed; + /// The distance after which the runback protection is triggered. + private readonly double RunbackDistance; + + /// The distance after which the rollforward protection is triggered. + private readonly double RollforwardDistance; + /// Whether ATO is available or not on the train. private readonly bool AtoAvailable; @@ -170,13 +185,18 @@ namespace OpenbveFcmbTrainPlugin private int AiBrakeNotch; /// Creates an instance of the Bombardier ATC device. + /// The length of the train, in meters. /// The maximum speed in YARD mode, in km/h. + /// The distance after which the runback protection is triggered, in meters. + /// The distance after which the rollforward protection is triggered, in meters. /// The list of signal codes recognised by the device. /// Whether ATO is available or not. - internal AtcDimetronic(double trainLength, Speed yardMaxSpeed, List signalCodes, bool atoAvailable) + internal AtcDimetronic(double trainLength, Speed yardMaxSpeed, double runbackDistance, double rollforwardDistance, List signalCodes, bool atoAvailable) { TrainLength = trainLength; YardMaximumSpeed = yardMaxSpeed; + RunbackDistance = runbackDistance; + RollforwardDistance = rollforwardDistance; SignalCodes = signalCodes; AtoAvailable = atoAvailable; } @@ -192,18 +212,20 @@ namespace OpenbveFcmbTrainPlugin { // Initialize device on start DeviceState = DeviceStates.NoMode; + // Reset runback and rollforward detection + RunbackLocation = train.State.Location; + RollforwardLocation = train.State.Location; } // Update train location - // TODO: implement runback/rollfoward protection TrainLocation = train.State.Location; double speed = train.State.Speed.KilometersPerHour; bool stopped = speed < 0.05; - // Speed limit enforcement if (DeviceState == DeviceStates.YARD || DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO) { + // Speed limit enforcement if (AtcControlState == AtcControlStates.Released && speed > CurrentSpeedCode.WarningOn.KilometersPerHour) { // Cut power above warning on threshold @@ -219,6 +241,36 @@ namespace OpenbveFcmbTrainPlugin // Unselect driving mode to apply emergency brake if overspeeding DeviceState = DeviceStates.NoMode; } + + // Runback protection + if ((train.PhysicalHandles.Reverser == 1 && TrainLocation > RunbackLocation) || (train.PhysicalHandles.Reverser == -1 && TrainLocation < RunbackLocation)) + { + // The train is moving in the correct direction, update location + RunbackLocation = TrainLocation; + } + if ((train.PhysicalHandles.Reverser >= 0 && TrainLocation < RunbackLocation - RunbackDistance) || (train.PhysicalHandles.Reverser <= 0 && TrainLocation > RunbackLocation + RunbackDistance)) + { + // The train is moving in the incorrect direction, reset driving mode + DeviceState = DeviceStates.NoMode; + } + + // Rollforward protection + if (train.PhysicalHandles.BrakeNotch > 0 || train.PhysicalHandles.PowerNotch > 0) + { + // The train has a power/brake notch applied, movement is expected + RollforwardTrigger = false; + RollforwardLocation = TrainLocation; + } + else if (stopped) + { + // The train is stopped but without power or brakes, start checking for unintended rolling + RollforwardTrigger = true; + } + if (RollforwardTrigger && (TrainLocation > RollforwardLocation + RollforwardDistance || TrainLocation < RollforwardLocation - RollforwardDistance)) + { + // The train is rolling unintendedly, reset driving mode + DeviceState = DeviceStates.NoMode; + } } // Brake application diff --git a/src/Managers/ConfigManager.cs b/src/Managers/ConfigManager.cs index a3a1754..82ba676 100644 --- a/src/Managers/ConfigManager.cs +++ b/src/Managers/ConfigManager.cs @@ -35,6 +35,8 @@ namespace OpenbveFcmbTrainPlugin internal int AtcBombardierBlinkTime = 500; internal Speed AtcDimetronicYardSpeedLimit = new Speed(25 / 3.6); + internal double AtcDimetronicRunbackDistance = 3; + internal double AtcDimetronicRollforwardDistance = 100; internal bool AtcDimetronicAtoAvailable; internal List AtcDimetronicSignalCodes = new List(); } @@ -222,6 +224,22 @@ namespace OpenbveFcmbTrainPlugin } } break; + case "runbackdistance": + { + if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double a)) + { + PluginSettings.AtcDimetronicRunbackDistance = a; + } + } + break; + case "rollforwarddistance": + { + if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double a)) + { + PluginSettings.AtcDimetronicRollforwardDistance = a; + } + } + break; case "atoavailable": PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0; break; diff --git a/src/Train/Train.cs b/src/Train/Train.cs index 00aa189..1d0ff1c 100644 --- a/src/Train/Train.cs +++ b/src/Train/Train.cs @@ -98,7 +98,7 @@ namespace OpenbveFcmbTrainPlugin } if (settings.AtcDimetronicDeviceEnabled) { - Devices.Add(new AtcDimetronic(settings.TrainLength, settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable)); + Devices.Add(new AtcDimetronic(settings.TrainLength, settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicRunbackDistance, settings.AtcDimetronicRollforwardDistance, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable)); } }