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));
}
}