From be7003669e236331cb60f9dfdec07ac798cf4f55 Mon Sep 17 00:00:00 2001 From: Marc Riera Date: Sat, 28 Dec 2024 13:06:54 +0100 Subject: [PATCH] ATC Dimetronic: ATO init --- src/Devices/AtcDimetronic.cs | 110 +++++++++++++++++++++++++++++------ 1 file changed, 91 insertions(+), 19 deletions(-) diff --git a/src/Devices/AtcDimetronic.cs b/src/Devices/AtcDimetronic.cs index dfd2dd8..aa4ad61 100644 --- a/src/Devices/AtcDimetronic.cs +++ b/src/Devices/AtcDimetronic.cs @@ -53,6 +53,23 @@ namespace OpenbveFcmbTrainPlugin /// The current state of the track. private TrackStates TrackState; + /// Represents the state of ATO. + private enum AtoStates + { + Inactive, + AwaitingStartup, + IncreaseSpeed, + MaintainSpeed, + ReduceSpeed, + StopApproach + } + + /// The current state of ATO. + private AtoStates AtoState; + + /// Whether ATO knows the precise position of the train or not. + private bool AtoPositionKnown; + /// The current position of the train. private double TrainLocation; @@ -90,13 +107,13 @@ namespace OpenbveFcmbTrainPlugin internal Speed WarningOn { get; private set; } internal Speed WarningOff { get; private set; } internal Speed TargetLimit { get; private set; } - internal double TargetDistance { get; private set; } + internal double TargetPosition { get; private set; } internal SpeedCode(Speed limit, Speed target, double distance) { CurrentLimit = limit; TargetLimit = target; - TargetDistance = distance; + TargetPosition = distance; if (limit == target) { // Constant speed @@ -116,10 +133,10 @@ namespace OpenbveFcmbTrainPlugin } /// Updates the ATC speed code. - /// The distance to the end of the signalling block. - internal void Update(double distance) + /// The position of the end of the signalling block. + internal void Update(double position) { - TargetDistance = distance; + TargetPosition = position; } } @@ -227,13 +244,19 @@ namespace OpenbveFcmbTrainPlugin // Update train location TrainLocation = train.State.Location; + // If ATO is not the current mode, it should be in inactive state + if (DeviceState != DeviceStates.ATO) + { + AtoState = AtoStates.Inactive; + } + double speed = train.State.Speed.KilometersPerHour; bool stopped = speed < 0.05; if (DeviceState == DeviceStates.YARD || DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO) { // Speed limit enforcement - if (AtcControlState == AtcControlStates.Released && speed > CurrentSpeedCode.WarningOn.KilometersPerHour) + if (AtcControlState == AtcControlStates.Released && speed > CurrentSpeedCode.WarningOn.KilometersPerHour && DeviceState != DeviceStates.ATO) { // Cut power above warning on threshold and play alarm AtcControlState = AtcControlStates.NoPowerAlarm; @@ -278,6 +301,16 @@ namespace OpenbveFcmbTrainPlugin // The train is rolling unintendedly, reset driving mode DeviceState = DeviceStates.NoMode; } + + // Accidental door opening protection + if (train.DoorState != DoorStates.None) + { + RequestedBrakeNotch = stopped ? train.Specs.BrakeNotches + 1 : train.ServiceBrakeNotch; + } + else + { + RequestedBrakeNotch = -1; + } } // Brake application @@ -320,28 +353,29 @@ namespace OpenbveFcmbTrainPlugin case DeviceStates.YARD: train.ContinuousProtection = false; train.VigilanceOverride = false; - // Apply brake if any door opens - if (train.DoorState != DoorStates.None) - { - RequestedBrakeNotch = stopped ? train.Specs.BrakeNotches + 1 : train.ServiceBrakeNotch; - } - // If the train is not moving, brakes are released - if (stopped) - { - AtcControlState = AtcControlStates.Released; - } break; // ATC device is in ATP (M+ATP) driving mode case DeviceStates.ATP: train.ContinuousProtection = true; train.VigilanceOverride = false; CurrentSpeedCode = GetSpeedCodeFromAspect(); + // If reverser is not forward, unselect mode + if (train.PhysicalHandles.Reverser != 1) + { + DeviceState = DeviceStates.NoMode; + } break; // ATC device is in ATO driving mode case DeviceStates.ATO: train.ContinuousProtection = true; train.VigilanceOverride = true; CurrentSpeedCode = GetSpeedCodeFromAspect(); + ProcessAto(train, route); + // If reverser is not forward or emergency brake is applied, unselect mode + if (train.PhysicalHandles.Reverser != 1 || train.PhysicalHandles.BrakeNotch > train.Specs.BrakeNotches) + { + DeviceState = DeviceStates.NoMode; + } break; } @@ -389,6 +423,7 @@ namespace OpenbveFcmbTrainPlugin if (train.PhysicalHandles.Reverser == 1 || train.PhysicalHandles.Reverser == -1) { DeviceState = DeviceStates.YARD; + AtcControlState = AtcControlStates.Released; // Update ATC speed code CurrentSpeedCode = new SpeedCode(YardMaximumSpeed, YardMaximumSpeed); } @@ -416,7 +451,7 @@ namespace OpenbveFcmbTrainPlugin // Allow change when the train is stopped in ATP mode if (DeviceState == DeviceStates.ATP && stopped && AtoAvailable) { - if (train.PhysicalHandles.Reverser == 1 && TrackState > TrackStates.Unprotected) + if (train.PhysicalHandles.Reverser == 1 && TrackState > TrackStates.Unprotected && train.PhysicalHandles.BrakeNotch <= train.Specs.BrakeNotches) { DeviceState = DeviceStates.ATO; } @@ -510,6 +545,16 @@ namespace OpenbveFcmbTrainPlugin { data.Handles.Reverser = 1; data.Response = AIResponse.Short; + return; + } + + // Acknowledge overspeed alarm + if (AtcControlState == AtcControlStates.NoPowerAlarm) + { + KeyChange(VirtualKeys.B1, true, train); + data.Response = AIResponse.Long; + KeyChange(VirtualKeys.B1, false, train); + return; } switch (DeviceState) @@ -524,6 +569,7 @@ namespace OpenbveFcmbTrainPlugin KeyChange(VirtualKeys.I, true, train); data.Response = AIResponse.Short; KeyChange(VirtualKeys.I, false, train); + return; } break; case DeviceStates.YARD: @@ -537,7 +583,7 @@ namespace OpenbveFcmbTrainPlugin KeyChange(VirtualKeys.J, true, train); data.Response = AIResponse.Short; KeyChange(VirtualKeys.J, false, train); - break; + return; } } CalculateAiNotches(data, train, route); @@ -553,7 +599,7 @@ namespace OpenbveFcmbTrainPlugin KeyChange(VirtualKeys.I, true, train); data.Response = AIResponse.Short; KeyChange(VirtualKeys.I, false, train); - break; + return; } } CalculateAiNotches(data, train, route); @@ -626,5 +672,31 @@ namespace OpenbveFcmbTrainPlugin } return new SpeedCode(new Speed(0), new Speed(0)); } + + /// Processes ATO orders. + private void ProcessAto(Train train, Route route) + { + double speed = train.State.Speed.KilometersPerHour; + bool stopped = speed < 0.05; + + Speed limit = CurrentSpeedCode.CurrentLimit; + Speed target = CurrentSpeedCode.TargetLimit; + double distance = CurrentSpeedCode.TargetPosition - TrainLocation; + + switch (AtoState) + { + case AtoStates.Inactive: + // Keep train still + RequestedPowerNotch = 0; + RequestedBrakeNotch = train.Specs.BrakeNotches + 1; + + // If the train is stopped, doors are closed and signal is clear, change to startup state + if (stopped && train.DoorState == DoorStates.None && target.KilometersPerHour > 0) + { + AtoState = AtoStates.AwaitingStartup; + } + break; + } + } } }