diff --git a/src/Devices/AtcBombardier.cs b/src/Devices/AtcBombardier.cs index 719bedd..34aa334 100644 --- a/src/Devices/AtcBombardier.cs +++ b/src/Devices/AtcBombardier.cs @@ -1,5 +1,4 @@ -using System; -using OpenBveApi.Runtime; +using OpenBveApi.Runtime; namespace OpenbveFcmbTrainPlugin { @@ -26,23 +25,25 @@ namespace OpenbveFcmbTrainPlugin /// The current state of the device. private DeviceStates DeviceState; - /// Represents the state of the device. - private enum AtcBrakeStates + /// Represents the state of the ATC control. + private enum AtcControlStates { /// The brakes are released. Released, + /// The power is cut. + NoPower, /// The service brake is applied and can be released. - Service, + BrakeService, /// The service brake is applied and cannot be released. - ServiceNoRelease, + BrakeServiceNoRelease, /// The service brake is fully applied. - Full, + BrakeFull, /// The emergency brake is applied. - Emergency, + BrakeEmergency, } - /// The current state of the ATC brake. - private AtcBrakeStates AtcBrakeState; + /// The current state of the ATC control. + private AtcControlStates AtcControlState; /// The time needed by the ATC device to initialize, in seconds. private double InitializationTime = 30; @@ -75,20 +76,68 @@ namespace OpenbveFcmbTrainPlugin DeviceState = DeviceStates.Initializing; } + double speed = train.State.Speed.KilometersPerHour; + bool stopped = speed < 0.05; + + // Speed limit calculation + // By default, use YARD mode speed limit + double limit = 25; + double powerLimit = limit - 2; + double releaseLimit = limit - 5; + double emergencyLimit = limit + 4; + + // Speed limit enforcement + if (DeviceState == DeviceStates.YARD || DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO) + { + if (AtcControlState == AtcControlStates.Released && speed >= powerLimit) + { + // Cut power on power limit + AtcControlState = AtcControlStates.NoPower; + } + if (AtcControlState == AtcControlStates.NoPower && speed < powerLimit) + { + // Stop cutting power below power limit + AtcControlState = AtcControlStates.Released; + } + if (speed > limit && speed < emergencyLimit) + { + // Apply service brake on limit + AtcControlState = AtcControlStates.BrakeServiceNoRelease; + } + if (speed > emergencyLimit) + { + // Unselect driving mode to apply emergency brake if overspeeding + DeviceState = DeviceStates.Initialized; + } + + // Allow brake release under defined threshold + if (AtcControlState == AtcControlStates.BrakeServiceNoRelease && speed < releaseLimit) + { + AtcControlState = AtcControlStates.BrakeService; + } + } + // Brake application if (DeviceState != DeviceStates.Override) { - switch (AtcBrakeState) + switch (AtcControlState) { - case AtcBrakeStates.Released: + case AtcControlStates.Released: RequestedBrakeNotch = -1; + RequestedPowerNotch = -1; break; - case AtcBrakeStates.Service: - case AtcBrakeStates.ServiceNoRelease: + case AtcControlStates.NoPower: + RequestedBrakeNotch = -1; + RequestedPowerNotch = 0; + break; + case AtcControlStates.BrakeService: + case AtcControlStates.BrakeServiceNoRelease: RequestedBrakeNotch = train.ServiceBrakeNotch; + RequestedPowerNotch = 0; break; - case AtcBrakeStates.Emergency: + case AtcControlStates.BrakeEmergency: RequestedBrakeNotch = train.Specs.BrakeNotches + 1; + RequestedPowerNotch = 0; break; } } @@ -108,7 +157,7 @@ namespace OpenbveFcmbTrainPlugin train.ContinuousProtection = false; train.VigilanceOverride = false; // Apply emergency brake during initialization - AtcBrakeState = AtcBrakeStates.Emergency; + AtcControlState = AtcControlStates.BrakeEmergency; // Wait during initialization time InitializationCounter += elapsedTime.Seconds; // If initialization is complete, change the state of the device @@ -122,15 +171,15 @@ namespace OpenbveFcmbTrainPlugin case DeviceStates.Initialized: train.ContinuousProtection = false; train.VigilanceOverride = false; - // Apply service brake while no driving mode is selected - AtcBrakeState = AtcBrakeStates.ServiceNoRelease; + // Apply service/emergency brake while no driving mode is selected + AtcControlState = stopped ? AtcControlStates.BrakeServiceNoRelease : AtcControlStates.BrakeEmergency; break; // ATC device is in YARD (M+25) driving mode case DeviceStates.YARD: train.ContinuousProtection = false; train.VigilanceOverride = false; // If the train is not moving, count idle time - if (train.State.Speed.KilometersPerHour < 0.05) + if (stopped) { YardIdleCounter += elapsedTime.Seconds; } @@ -141,16 +190,27 @@ namespace OpenbveFcmbTrainPlugin // If above idle time, apply the service brake if (YardIdleCounter >= YardIdleTime) { - AtcBrakeState = AtcBrakeStates.Service; + AtcControlState = AtcControlStates.BrakeService; } else { - AtcBrakeState = AtcBrakeStates.Released; + AtcControlState = AtcControlStates.Released; } // Apply brake if any door opens if (train.DoorState != DoorStates.None) { - RequestedBrakeNotch = train.State.Speed.KilometersPerHour < 0.05 ? train.Specs.BrakeNotches + 1 : train.ServiceBrakeNotch; + RequestedBrakeNotch = stopped ? train.Specs.BrakeNotches + 1 : train.ServiceBrakeNotch; + } + // Speed limitations + if (speed > 23) + { + // Cut power over 23 km/h + RequestedPowerNotch = 0; + if (speed > 25) + { + // Apply service brake over 25 km/h + AtcControlState = AtcControlStates.BrakeServiceNoRelease; + } } break; // ATC device is in ATP (M+ATP) driving mode @@ -173,20 +233,20 @@ namespace OpenbveFcmbTrainPlugin // Panel indicators train.Panel[25] = DeviceState == DeviceStates.Override ? 1 : 0; train.Panel[26] = DeviceState == DeviceStates.YARD ? 1 : 0; - train.Panel[26] += DeviceState == DeviceStates.Initialized && train.State.Speed.KilometersPerHour < 0.05 && blink ? 1 : 0; + train.Panel[26] += DeviceState == DeviceStates.Initialized && stopped && blink ? 1 : 0; train.Panel[27] = DeviceState == DeviceStates.ATP ? 1 : 0; train.Panel[28] = DeviceState == DeviceStates.ATP ? 1 : 0; - switch (AtcBrakeState) + switch (AtcControlState) { - case AtcBrakeStates.Released: - case AtcBrakeStates.Emergency: + case AtcControlStates.Released: + case AtcControlStates.BrakeEmergency: train.Panel[32] = 0; break; - case AtcBrakeStates.ServiceNoRelease: - case AtcBrakeStates.Full: + case AtcControlStates.BrakeServiceNoRelease: + case AtcControlStates.BrakeFull: train.Panel[32] = 1; break; - case AtcBrakeStates.Service: + case AtcControlStates.BrakeService: train.Panel[32] = blink ? 1 : 0; break; } @@ -236,9 +296,9 @@ namespace OpenbveFcmbTrainPlugin if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key]) { // Allow brake release under certain conditions - if (AtcBrakeState == AtcBrakeStates.Service) + if (AtcControlState == AtcControlStates.BrakeService) { - AtcBrakeState = AtcBrakeStates.Released; + AtcControlState = AtcControlStates.Released; // Reset YARD idle counter YardIdleCounter = 0; }