Bombardier ATC
parent
3aae76416c
commit
f1e9c3e654
|
@ -0,0 +1,287 @@
|
||||||
|
using System;
|
||||||
|
using OpenBveApi.Runtime;
|
||||||
|
|
||||||
|
namespace OpenbveFcmbTrainPlugin
|
||||||
|
{
|
||||||
|
/// <summary>A device simulating ATC by Bombardier.</summary>
|
||||||
|
internal class AtcBombardier : Device
|
||||||
|
{
|
||||||
|
/// <summary>Represents the state of the device.</summary>
|
||||||
|
private enum DeviceStates
|
||||||
|
{
|
||||||
|
/// <summary>The device is being overriden.</summary>
|
||||||
|
Override,
|
||||||
|
/// <summary>The device is initializing.</summary>
|
||||||
|
Initializing,
|
||||||
|
/// <summary>The device has been initialized and no driving mode is selected.</summary>
|
||||||
|
Initialized,
|
||||||
|
/// <summary>The device is in YARD (M+25) driving mode.</summary>
|
||||||
|
YARD,
|
||||||
|
/// <summary>The device is in ATP (M+ATP) driving mode.</summary>
|
||||||
|
ATP,
|
||||||
|
/// <summary>The device is in ATO mode.</summary>
|
||||||
|
ATO,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The current state of the device.</summary>
|
||||||
|
private DeviceStates DeviceState;
|
||||||
|
|
||||||
|
/// <summary>Represents the state of the device.</summary>
|
||||||
|
private enum AtcBrakeStates
|
||||||
|
{
|
||||||
|
/// <summary>The brakes are released.</summary>
|
||||||
|
Released,
|
||||||
|
/// <summary>The service brake is applied and can be released.</summary>
|
||||||
|
Service,
|
||||||
|
/// <summary>The service brake is applied and cannot be released.</summary>
|
||||||
|
ServiceNoRelease,
|
||||||
|
/// <summary>The service brake is fully applied.</summary>
|
||||||
|
Full,
|
||||||
|
/// <summary>The emergency brake is applied.</summary>
|
||||||
|
Emergency,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The current state of the ATC brake.</summary>
|
||||||
|
private AtcBrakeStates AtcBrakeState;
|
||||||
|
|
||||||
|
/// <summary>The time needed by the ATC device to initialize, in seconds.</summary>
|
||||||
|
private double InitializationTime = 30;
|
||||||
|
|
||||||
|
/// <summary>A counter to keep track of initialization time, in seconds.</summary>
|
||||||
|
private double InitializationCounter;
|
||||||
|
|
||||||
|
/// <summary>The blinking time for lamps, in milliseconds.</summary>
|
||||||
|
private double BlinkTime = 500;
|
||||||
|
|
||||||
|
/// <summary>A counter to keep track of blink time, in milliseconds.</summary>
|
||||||
|
private double BlinkCounter;
|
||||||
|
|
||||||
|
/// <summary>The time after which YARD mode enters idle state and engages the service brake, in seconds.</summary>
|
||||||
|
private double YardIdleTime = 60;
|
||||||
|
|
||||||
|
/// <summary>A counter to keep track of YARD mode idle time, in seconds.</summary>
|
||||||
|
private double YardIdleCounter;
|
||||||
|
|
||||||
|
/// <summary>Is called when the device state should be updated.</summary>
|
||||||
|
/// <param name="train">The current train.</param>
|
||||||
|
/// <param name="route">The current route.</param>
|
||||||
|
/// <param name="init">Whether the device should initialize.</param>
|
||||||
|
/// <param name="elapsedTime">The time elapsed since the previous call.</param>
|
||||||
|
internal override void Update(Train train, Route route, bool init, Time elapsedTime)
|
||||||
|
{
|
||||||
|
if (init)
|
||||||
|
{
|
||||||
|
// Initialize device on start
|
||||||
|
DeviceState = DeviceStates.Initializing;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (DeviceState)
|
||||||
|
{
|
||||||
|
// ATC device is disabled (also called "Special Mode")
|
||||||
|
case DeviceStates.Override:
|
||||||
|
train.ContinuousProtection = false;
|
||||||
|
train.VigilanceOverride = false;
|
||||||
|
// Release control of the brakes and power
|
||||||
|
RequestedBrakeNotch = -1;
|
||||||
|
RequestedPowerNotch = -1;
|
||||||
|
break;
|
||||||
|
// ATC device is initializing
|
||||||
|
case DeviceStates.Initializing:
|
||||||
|
train.ContinuousProtection = false;
|
||||||
|
train.VigilanceOverride = false;
|
||||||
|
// Apply emergency brake during initialization
|
||||||
|
AtcBrakeState = AtcBrakeStates.Emergency;
|
||||||
|
// Wait during initialization time
|
||||||
|
InitializationCounter += elapsedTime.Seconds;
|
||||||
|
// If initialization is complete, change the state of the device
|
||||||
|
if (InitializationCounter > InitializationTime)
|
||||||
|
{
|
||||||
|
DeviceState = DeviceStates.Initialized;
|
||||||
|
InitializationCounter = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// ATC device is initialized and a driving mode is required
|
||||||
|
case DeviceStates.Initialized:
|
||||||
|
train.ContinuousProtection = false;
|
||||||
|
train.VigilanceOverride = false;
|
||||||
|
// Apply service brake while no driving mode is selected
|
||||||
|
AtcBrakeState = AtcBrakeStates.ServiceNoRelease;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
YardIdleCounter += elapsedTime.Seconds;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
YardIdleCounter = 0;
|
||||||
|
}
|
||||||
|
// If above idle time, apply the service brake
|
||||||
|
if (YardIdleCounter >= YardIdleTime)
|
||||||
|
{
|
||||||
|
AtcBrakeState = AtcBrakeStates.Service;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AtcBrakeState = AtcBrakeStates.Released;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// ATC device is in ATP (M+ATP) driving mode
|
||||||
|
case DeviceStates.ATP:
|
||||||
|
train.ContinuousProtection = true;
|
||||||
|
train.VigilanceOverride = false;
|
||||||
|
break;
|
||||||
|
// ATC device is in ATO driving mode
|
||||||
|
case DeviceStates.ATO:
|
||||||
|
train.ContinuousProtection = true;
|
||||||
|
train.VigilanceOverride = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DeviceState != DeviceStates.Override)
|
||||||
|
{
|
||||||
|
// Brake application
|
||||||
|
switch (AtcBrakeState)
|
||||||
|
{
|
||||||
|
case AtcBrakeStates.Released:
|
||||||
|
RequestedBrakeNotch = -1;
|
||||||
|
break;
|
||||||
|
case AtcBrakeStates.Service:
|
||||||
|
case AtcBrakeStates.ServiceNoRelease:
|
||||||
|
RequestedBrakeNotch = train.ServiceBrakeNotch;
|
||||||
|
break;
|
||||||
|
case AtcBrakeStates.Emergency:
|
||||||
|
RequestedBrakeNotch = train.Specs.BrakeNotches + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Blinking light animation
|
||||||
|
BlinkCounter += elapsedTime.Milliseconds;
|
||||||
|
bool blink = BlinkCounter >= BlinkTime;
|
||||||
|
if (BlinkCounter > (BlinkTime * 2)) BlinkCounter = 0;
|
||||||
|
|
||||||
|
// 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[27] = DeviceState == DeviceStates.ATP ? 1 : 0;
|
||||||
|
train.Panel[28] = DeviceState == DeviceStates.ATP ? 1 : 0;
|
||||||
|
switch (AtcBrakeState)
|
||||||
|
{
|
||||||
|
case AtcBrakeStates.Released:
|
||||||
|
case AtcBrakeStates.Emergency:
|
||||||
|
train.Panel[32] = 0;
|
||||||
|
break;
|
||||||
|
case AtcBrakeStates.ServiceNoRelease:
|
||||||
|
case AtcBrakeStates.Full:
|
||||||
|
train.Panel[32] = 1;
|
||||||
|
break;
|
||||||
|
case AtcBrakeStates.Service:
|
||||||
|
train.Panel[32] = blink ? 1 : 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>Is called when the state of a key changes.</summary>
|
||||||
|
/// <param name="key">The key.</param>
|
||||||
|
/// <param name="pressed">Whether the key is pressed or released.</param>
|
||||||
|
/// <param name="train">The current train.</param>
|
||||||
|
internal override void KeyChange(VirtualKeys key, bool pressed, Train train)
|
||||||
|
{
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case VirtualKeys.I:
|
||||||
|
// YARD (M+25) mode selection button
|
||||||
|
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
|
||||||
|
{
|
||||||
|
if (DeviceState == DeviceStates.Initialized && train.State.Speed.KilometersPerHour < 0.05)
|
||||||
|
{
|
||||||
|
DeviceState = DeviceStates.YARD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VirtualKeys.J:
|
||||||
|
// ATP (M+ATP) mode selection button
|
||||||
|
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VirtualKeys.K:
|
||||||
|
// ATO mode selection button
|
||||||
|
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VirtualKeys.L:
|
||||||
|
// ATO start button
|
||||||
|
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
|
||||||
|
{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VirtualKeys.B1:
|
||||||
|
// ATC brake release
|
||||||
|
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
|
||||||
|
{
|
||||||
|
// Allow brake release under certain conditions
|
||||||
|
if (AtcBrakeState == AtcBrakeStates.Service)
|
||||||
|
{
|
||||||
|
AtcBrakeState = AtcBrakeStates.Released;
|
||||||
|
// Reset YARD idle counter
|
||||||
|
YardIdleCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case VirtualKeys.C1:
|
||||||
|
// Override toggle
|
||||||
|
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
|
||||||
|
{
|
||||||
|
switch (DeviceState)
|
||||||
|
{
|
||||||
|
case DeviceStates.Initializing:
|
||||||
|
case DeviceStates.Initialized:
|
||||||
|
case DeviceStates.YARD:
|
||||||
|
// Override device if possible
|
||||||
|
if (train.State.Speed.KilometersPerHour < 0.05 && train.PhysicalHandles.PowerNotch == 0)
|
||||||
|
{
|
||||||
|
DeviceState = DeviceStates.Override;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DeviceStates.Override:
|
||||||
|
// Disable override if possible
|
||||||
|
if (train.State.Speed.KilometersPerHour < 0.05 && train.PhysicalHandles.PowerNotch == 0)
|
||||||
|
{
|
||||||
|
DeviceState = DeviceStates.Initializing;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Is called when a beacon is passed.</summary>
|
||||||
|
/// <param name="beacon">The beacon data.</param>
|
||||||
|
internal override void SetBeacon(BeaconData beacon)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Is called when the device should perform the AI.</summary>
|
||||||
|
/// <param name="data">The AI data.</param>
|
||||||
|
/// <param name="train">The current train.</param>
|
||||||
|
/// <param name="route">The current route.</param>
|
||||||
|
internal override void PerformAI(AIData data, Train train, Route route)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,18 +64,21 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
/// <param name="reverser">The new reverser position.</param>
|
/// <param name="reverser">The new reverser position.</param>
|
||||||
public void SetReverser(int reverser)
|
public void SetReverser(int reverser)
|
||||||
{
|
{
|
||||||
|
Train.SetReverser(reverser);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Is called when the driver changes the power notch.</summary>
|
/// <summary>Is called when the driver changes the power notch.</summary>
|
||||||
/// <param name="powerNotch">The new power notch.</param>
|
/// <param name="powerNotch">The new power notch.</param>
|
||||||
public void SetPower(int powerNotch)
|
public void SetPower(int powerNotch)
|
||||||
{
|
{
|
||||||
|
Train.SetPower(powerNotch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Is called when the driver changes the brake notch.</summary>
|
/// <summary>Is called when the driver changes the brake notch.</summary>
|
||||||
/// <param name="brakeNotch">The new brake notch.</param>
|
/// <param name="brakeNotch">The new brake notch.</param>
|
||||||
public void SetBrake(int brakeNotch)
|
public void SetBrake(int brakeNotch)
|
||||||
{
|
{
|
||||||
|
Train.SetBrake(brakeNotch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Is called when a virtual key is pressed.</summary>
|
/// <summary>Is called when a virtual key is pressed.</summary>
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
<Compile Include="Devices\TrainStop.cs" />
|
<Compile Include="Devices\TrainStop.cs" />
|
||||||
<Compile Include="Devices\Deadman.cs" />
|
<Compile Include="Devices\Deadman.cs" />
|
||||||
<Compile Include="Route\Route.cs" />
|
<Compile Include="Route\Route.cs" />
|
||||||
|
<Compile Include="Devices\AtcBombardier.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Devices\" />
|
<Folder Include="Devices\" />
|
||||||
|
|
|
@ -6,6 +6,14 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
/// <summary>Represents a train that is simulated by this plugin.</summary>
|
/// <summary>Represents a train that is simulated by this plugin.</summary>
|
||||||
internal class Train
|
internal class Train
|
||||||
{
|
{
|
||||||
|
/// <summary>Represents the driver's handles.</summary>
|
||||||
|
internal class DriverHandles
|
||||||
|
{
|
||||||
|
internal int Reverser;
|
||||||
|
internal int PowerNotch;
|
||||||
|
internal int BrakeNotch;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>The train panel variables.</summary>
|
/// <summary>The train panel variables.</summary>
|
||||||
internal int[] Panel;
|
internal int[] Panel;
|
||||||
|
|
||||||
|
@ -27,12 +35,18 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
/// <summary>The devices equipped in the train.</summary>
|
/// <summary>The devices equipped in the train.</summary>
|
||||||
private List<Device> Devices;
|
private List<Device> Devices;
|
||||||
|
|
||||||
|
/// <summary>The physical handles of the train.</summary>
|
||||||
|
internal DriverHandles PhysicalHandles { get; private set; }
|
||||||
|
|
||||||
/// <summary>Whether the train's vigilance device is overridden.</summary>
|
/// <summary>Whether the train's vigilance device is overridden.</summary>
|
||||||
internal bool VigilanceOverride;
|
internal bool VigilanceOverride;
|
||||||
|
|
||||||
/// <summary>Whether the train is using a continuous protection system instead of an intermittent protection system.</summary>
|
/// <summary>Whether the train is using a continuous protection system instead of an intermittent protection system.</summary>
|
||||||
internal bool ContinuousProtection;
|
internal bool ContinuousProtection;
|
||||||
|
|
||||||
|
/// <summary>The service brake notch for ATC.</summary>
|
||||||
|
internal int ServiceBrakeNotch { get; private set; }
|
||||||
|
|
||||||
/// <summary>Creates a new train with the device configuration provided.</summary>
|
/// <summary>Creates a new train with the device configuration provided.</summary>
|
||||||
/// <param name="panel">The array of panel variables.</pa
|
/// <param name="panel">The array of panel variables.</pa
|
||||||
internal Train(int[] panel)
|
internal Train(int[] panel)
|
||||||
|
@ -40,10 +54,12 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
Specs = new VehicleSpecs(0, BrakeTypes.ElectromagneticStraightAirBrake, 0, false, 0);
|
Specs = new VehicleSpecs(0, BrakeTypes.ElectromagneticStraightAirBrake, 0, false, 0);
|
||||||
State = new VehicleState(0.0, new Speed(0.0), 0.0, 0.0, 0.0, 0.0, 0.0);
|
State = new VehicleState(0.0, new Speed(0.0), 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||||
Panel = panel;
|
Panel = panel;
|
||||||
|
PhysicalHandles = new DriverHandles();
|
||||||
Devices = new List<Device>();
|
Devices = new List<Device>();
|
||||||
Devices.Add(new Doors());
|
Devices.Add(new Doors());
|
||||||
Devices.Add(new Deadman());
|
Devices.Add(new Deadman());
|
||||||
Devices.Add(new TrainStop());
|
Devices.Add(new TrainStop());
|
||||||
|
Devices.Add(new AtcBombardier());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Is called when the train should initialize.</summary>
|
/// <summary>Is called when the train should initialize.</summary>
|
||||||
|
@ -58,6 +74,9 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
internal void SetVehicleSpecs(VehicleSpecs specs)
|
internal void SetVehicleSpecs(VehicleSpecs specs)
|
||||||
{
|
{
|
||||||
Specs = specs;
|
Specs = specs;
|
||||||
|
|
||||||
|
// Set the service brake notch for ATC
|
||||||
|
ServiceBrakeNotch = specs.BrakeNotches > 1 ? specs.BrakeNotches - 1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Is called every frame.</summary>
|
/// <summary>Is called every frame.</summary>
|
||||||
|
@ -84,15 +103,24 @@ namespace OpenbveFcmbTrainPlugin
|
||||||
|
|
||||||
/// <summary>Is called when the driver changes the reverser.</summary>
|
/// <summary>Is called when the driver changes the reverser.</summary>
|
||||||
/// <param name="reverser">The new reverser position.</param>
|
/// <param name="reverser">The new reverser position.</param>
|
||||||
internal void SetReverser(int reverser) { }
|
internal void SetReverser(int reverser)
|
||||||
|
{
|
||||||
|
PhysicalHandles.Reverser = reverser;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Is called when the driver changes the power notch.</summary>
|
/// <summary>Is called when the driver changes the power notch.</summary>
|
||||||
/// <param name="powerNotch">The new power notch.</param>
|
/// <param name="powerNotch">The new power notch.</param>
|
||||||
internal void SetPower(int powerNotch) { }
|
internal void SetPower(int powerNotch)
|
||||||
|
{
|
||||||
|
PhysicalHandles.PowerNotch = powerNotch;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Is called when the driver changes the brake notch.</summary>
|
/// <summary>Is called when the driver changes the brake notch.</summary>
|
||||||
/// <param name="brakeNotch">The new brake notch.</param>
|
/// <param name="brakeNotch">The new brake notch.</param>
|
||||||
internal void SetBrake(int brakeNotch) { }
|
internal void SetBrake(int brakeNotch)
|
||||||
|
{
|
||||||
|
PhysicalHandles.BrakeNotch = brakeNotch;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Is called when a key is pressed.</summary>
|
/// <summary>Is called when a key is pressed.</summary>
|
||||||
/// <param name="key">The key.</param>
|
/// <param name="key">The key.</param>
|
||||||
|
|
Loading…
Reference in New Issue