diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 199c65a0c..79a73f1a0 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -2466,6 +2466,13 @@ class TMoverParameters { return false == StLinFlag && MainCircuitLampsEnabled(); } + // whether the cab command opening the main circuit opens it where the only cab switch of the circuit is the button + // closing it: on a diesel that's the starter button, and the command is the one way to stop an engine whose fuel pump + // starts on its own (eu07/maszyna#427). the other vehicles with such a button keep ignoring the command + bool MainCircuitOpensWithStarterOnly() const + { + return EngineType == TEngineType::DieselEngine || EngineType == TEngineType::DieselElectric; + } // whether the pumps a joint oil and fuel pump switch works, those not started automatically, are all switched on bool OilFuelPumpsEnabled() const { diff --git a/tests/unit/data/diesel_shunter.json b/tests/unit/data/diesel_shunter.json new file mode 100644 index 000000000..3cbcdb992 --- /dev/null +++ b/tests/unit/data/diesel_shunter.json @@ -0,0 +1,53 @@ +{ + "_comment": "Diesel shunter with a mechanical gearbox, made after the SM03 (Ls150): the fuel pump starts on its own with the engine, a converter run by the engine feeds the low voltage circuit, the only cab control of the engine is the starter button.", + "Param": { "Category": "train", "M": 23200, "Vmax": 25.68, "PWR": 111.855, "SandCap": 200 }, + "Dimensions": { "L": 6.94, "H": 3.21, "W": 2.97, "Cx": 0.3 }, + "Wheels": { "D": 0.94, "Tw": 1.435, "AIM": 250, "Axle": "B", "Ad": 2.5, "Bd": 2.5, "Rmin": 50, "BearingType": "Roll" }, + "Brake": { + "BrakeValve": "K", "NBpA": 2, "MBF": 85.0, "MaxBP": 3.5, "LocMaxBP": 5.0, "BCN": 1, "BCR": 0.114, "BCD": 0.12, "BCM": 10.0, + "HiPP": 5, "LoPP": 3.5, "Vv": 0.3, "MinCP": 7.0, "MaxCP": 8.0, "CompressorSpeed": 0.0125, "CompressorPower": "Main", + "BCS": 0.8, "BSA": 0, "BM": "P10-Bg", "BVV": 40, "BRE": 0.9 + }, + "BuffCoupl": { "CType": "Screw", "kB": 9200, "DmaxB": 0.15, "FmaxB": 740, "kC": 4800, "DmaxC": 0.15, "FmaxC": 780, "beta": 0.58, "AllowedFlag": 3 }, + "Cntrl": { + "BrakeSystem": "Pneumatic", "BDelay1": 15, "BDelay2": 4, "ASB": "Manual", "LocalBrake": "PneumaticBrake", "ManualBrake": "Yes", + "DynamicBrake": "Passive", "MCPN": 9, "SCPN": 7, "AutoRelay": "No", "IniCDelay": 0.5, "SCDelay": 0.1, "BrakeDelays": "P", + "BrakeHandle": "Knorr", "LocBrakeHandle": "Knorr", "FuelStart": "Automatic", "ConverterStart": "Automatic" + }, + "Light": { "Light": "Generator", "LGeneratorEngine": "ElectricSeriesMotor", "LMaxVoltage": 24, "LMaxCurrent": 100 }, + "Engine": { + "EngineType": "DieselEngine", "Trans": "1:1", "nmin": 900, "nmax": 1500, "nmax_cutoff": 1550, "AIM": 100, + "OilMinPressure": 0.343, "OilMaxPressure": 0.686, "WaterCoolingTemperature": 80, "WaterShutters": "yes", "WaterAuxCircuit": "no", + "HeatKFO": 160, "HeatKFO2": 180, "HeatKFS": 160, "HeatKFE": 7, "HeatKW": 2, "HeatKV": 0.3, "IsTC": "No", "EUS": 0.35, "EDS": 1.0 + }, + "_gears": "rows: gear, ratio, engagement speed, top speed; the even ones neutral", + "MotorParamTable": { + "minVelfullengage": 3.8, "engageDia": 1, "engageMaxForce": 800, "engagefriction": 1, + "rows": [ + [0, 0, 0, -1], + [1, 46.88, -1, 5.73], + [2, 0, 0, -1], + [3, 28.65, 2.9, 9.42], + [4, 0, 0, -1], + [5, 17.12, 4.7, 15.69], + [6, 0, 0, -1], + [7, 10.46, 10.6, 100] + ] + }, + "_throttle": "rows: position, fill, speed governor mode; position 0 idles", + "DList": { + "Size": 9, "Mmax": 784.5, "nMmax": 15, "Mnmax": 686.4, "nmax": 25, "nominalfill": 1, "Mstand": 200.0, + "rows": [ + [0, 0.1, 0], + [1, 0.2, 2], + [2, 0.3, 2], + [3, 0.4, 2], + [4, 0.5, 2], + [5, 0.6, 2], + [6, 0.7, 2], + [7, 0.8, 2], + [8, 0.9, 2], + [9, 1.0, 2] + ] + } +} diff --git a/tests/unit/test_engine_shutdown.cpp b/tests/unit/test_engine_shutdown.cpp new file mode 100644 index 000000000..9230330f4 --- /dev/null +++ b/tests/unit/test_engine_shutdown.cpp @@ -0,0 +1,74 @@ +#include "stdafx.h" +#include "doctest.h" +#include "vehicle.h" + +// stopping the engine of a diesel shunter like the SM03 (eu07/maszyna#427): its fuel pump starts on its own with the +// engine and the engine runs the converter which feeds the low voltage circuit, so neither the fuel pump switch nor the +// battery switch stop it. the cab has only the starter button, and the command opening the main circuit has to stop it + +namespace { + +// the shunter with its engine started from the cab and idling +test::vehicle running_shunter() { + test::vehicle shunter{test::definition::load("diesel_shunter")}; + shunter->CabOccupied = 1; + shunter->CabActivisation(); + shunter->BatterySwitch(true); + shunter->OilPumpSwitch(true); + shunter.run(20.0); // the oil pressure builds up + shunter->MainSwitch(true); + shunter.run(15.0); + return shunter; +} + +} // namespace + +TEST_CASE("engine shutdown: the shunter starts with the starter button") { + auto shunter{running_shunter()}; + REQUIRE(shunter->EngineType == TEngineType::DieselEngine); + REQUIRE(shunter->FuelPump.start_type == start_t::automatic); + CHECK(shunter->Mains); + CHECK(shunter->FuelPump.is_active); + CHECK(shunter->enrot > 0.9 * shunter->dizel_nmin); +} + +TEST_CASE("engine shutdown: neither the fuel pump switch nor the battery switch stop the engine") { + auto shunter{running_shunter()}; + shunter->FuelPumpSwitchOff(true, range_t::local); // the pump started automatically ignores its switch + shunter.run(10.0); + CHECK(shunter->Mains); + shunter->BatterySwitch(false); + shunter.run(10.0); + CHECK(shunter->Power110vIsAvailable); // the converter run by the engine keeps feeding the fuel pump + CHECK(shunter->Mains); + CHECK(shunter->enrot > 0.9 * shunter->dizel_nmin); +} + +TEST_CASE("engine shutdown: the command opening the main circuit stops the engine and it stays stopped") { + auto shunter{running_shunter()}; + REQUIRE(shunter->MainCircuitOpensWithStarterOnly()); // the cab passes the command on with only the starter button + CHECK(shunter->MainSwitch(false)); + shunter.run(20.0); + CHECK_FALSE(shunter->Mains); + CHECK_FALSE(shunter->FuelPump.is_active); + CHECK(shunter->enrot == 0.0); +} + +TEST_CASE("engine shutdown: the engine starts again after it was stopped") { + auto shunter{running_shunter()}; + shunter->MainSwitch(false); + shunter.run(20.0); + REQUIRE(shunter->enrot == 0.0); + shunter->MainSwitch(true); + shunter.run(15.0); + CHECK(shunter->Mains); + CHECK(shunter->enrot > 0.9 * shunter->dizel_nmin); +} + +TEST_CASE("engine shutdown: vehicles without a diesel keep ignoring the command with only the button closing the circuit") { + test::vehicle wagon{test::definition::load("wagon")}; + CHECK_FALSE(wagon->MainCircuitOpensWithStarterOnly()); + test::vehicle electric{test::definition::load("wagon").set("Engine", "EngineType", "ElectricSeriesMotor")}; + REQUIRE(electric->EngineType == TEngineType::ElectricSeriesMotor); + CHECK_FALSE(electric->MainCircuitOpensWithStarterOnly()); +} diff --git a/vehicle/Train.cpp b/vehicle/Train.cpp index 201b8972f..1b7d06a8f 100644 --- a/vehicle/Train.cpp +++ b/vehicle/Train.cpp @@ -3702,13 +3702,14 @@ void TTrain::OnCommand_linebreakeropen(TTrain *Train, command_data const &Comman { Train->ggMainButton.UpdateValue(0.0, Train->dsbSwitch); } - else if (Train->ggMainOnButton.SubModel != nullptr) + else if (Train->ggMainOnButton.SubModel != nullptr && false == Train->mvControlled->MainCircuitOpensWithStarterOnly()) { // NOTE: legacy behaviour, for vehicles equipped only with impulse close switch // it doesn't make any real sense to animate this one, but some people can't get over how there's no visual reaction to their keypress Train->ggMainOnButton.UpdateValue(1.0, Train->dsbSwitch); return; } + // a diesel with only the starter button gets its engine stopped. the button stays put: held down, it would start the engine again // play sound immediately when the switch is hit, not after release Train->fMainRelayTimer = 0.0f;