From 03d4720b3eef0adbaac0433f9dcc1e334df4de3b Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Wed, 11 Apr 2018 00:39:09 +0200 Subject: [PATCH] build 180411. basic oil pump, diesel engine startup procedure --- Driver.cpp | 11 +- DynObj.cpp | 54 ++++++--- DynObj.h | 2 + McZapkie/MOVER.h | 27 ++++- McZapkie/Mover.cpp | 268 +++++++++++++++++++++++++++++++-------------- Train.cpp | 88 +++++++++++---- Train.h | 4 + command.cpp | 3 + command.h | 3 + keyboardinput.cpp | 6 + mouseinput.cpp | 3 + simulation.cpp | 8 +- translation.h | 1 + uilayer.cpp | 10 +- version.h | 2 +- 15 files changed, 351 insertions(+), 139 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index c939958b..6967e5f1 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -2225,8 +2225,12 @@ bool TController::PrepareEngine() } if (AIControllFlag) { // część wykonawcza dla sterowania przez komputer - mvOccupied->BatterySwitch(true); - mvOccupied->FuelPumpSwitch( true ); + mvOccupied->BatterySwitch( true ); + if( ( mvOccupied->EngineType == DieselElectric ) + || ( mvOccupied->EngineType == DieselEngine ) ) { + mvOccupied->FuelPumpSwitch( true ); + mvOccupied->OilPumpSwitch( true ); + } if (mvControlling->EnginePowerSource.SourceType == CurrentCollector) { // jeśli silnikowy jest pantografującym mvControlling->PantFront( true ); @@ -2294,7 +2298,7 @@ bool TController::PrepareEngine() else if (false == mvControlling->Mains) { while (DecSpeed(true)) ; // zerowanie napędu - +/* if( ( mvOccupied->EngineType == DieselEngine ) || ( mvOccupied->EngineType == DieselElectric ) ) { // start helper devices before spinning up the engine @@ -2302,6 +2306,7 @@ bool TController::PrepareEngine() mvOccupied->ConverterSwitch( true ); mvOccupied->CompressorSwitch( true ); } +*/ if( mvOccupied->TrainType == dt_SN61 ) { // specjalnie dla SN61 żeby nie zgasł if( mvControlling->RList[ mvControlling->MainCtrlPos ].Mn == 0 ) { diff --git a/DynObj.cpp b/DynObj.cpp index c188cc77..f1d3ea43 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -4889,6 +4889,12 @@ void TDynamicObject::LoadMMediaFile( std::string BaseDir, std::string TypeName, m_powertrainsounds.engine_revving.owner( this ); } + else if( token == "oilpump:" ) { + // plik z dzwiekiem wentylatora, mnozniki i ofsety amp. i czest. + m_powertrainsounds.oil_pump.deserialize( parser, sound_type::single ); + m_powertrainsounds.oil_pump.owner( this ); + } + else if( ( token == "tractionmotor:" ) && ( MoverParameters->Power > 0 ) ) { // plik z dzwiekiem silnika, mnozniki i ofsety amp. i czest. @@ -5944,9 +5950,37 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub double frequency { 1.0 }; double volume { 0.0 }; + // oil pump + if( true == Vehicle.OilPump.is_active ) { + oil_pump + .pitch( oil_pump.m_frequencyoffset + oil_pump.m_frequencyfactor * 1.f ) + .gain( oil_pump.m_amplitudeoffset + oil_pump.m_amplitudefactor * 1.f ) + .play( sound_flags::exclusive | sound_flags::looping ); + } + else { + oil_pump.stop(); + } + // engine sounds - if( ( true == Vehicle.Mains ) - && ( false == Vehicle.dizel_enginestart ) ) { + // ignition + if( engine_state_last != Vehicle.Mains ) { + + if( true == Vehicle.Mains ) { + // main circuit/engine activation + // TODO: separate engine and main circuit + engine_ignition + .pitch( engine_ignition.m_frequencyoffset + engine_ignition.m_frequencyfactor * 1.f ) + .gain( engine_ignition.m_amplitudeoffset + engine_ignition.m_amplitudefactor * 1.f ) + .play( sound_flags::exclusive ); + } + else { + // main circuit/engine deactivation + engine_ignition.stop(); + } + engine_state_last = Vehicle.Mains; + } + // main engine sound + if( true == Vehicle.Mains ) { if( ( std::fabs( Vehicle.enrot ) > 0.01 ) // McZapkie-280503: zeby dla dumb dzialal silnik na jalowych obrotach @@ -6058,7 +6092,6 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub engine.stop(); } - // youBy - przenioslem, bo diesel tez moze miec turbo if( Vehicle.TurboTest > 0 ) { // udawanie turbo: @@ -6100,19 +6133,6 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub } } - // diesel startup - if( ( Vehicle.EngineType == DieselEngine ) - || ( Vehicle.EngineType == DieselElectric ) ) { - - if( true == Vehicle.dizel_enginestart ) { - engine_ignition - .pitch( engine_ignition.m_frequencyoffset + engine_ignition.m_frequencyfactor * 1.f ) - .gain( engine_ignition.m_amplitudeoffset + engine_ignition.m_amplitudefactor * 1.f ) - .play( sound_flags::exclusive ); - } - } - - if( Vehicle.dizel_engage > 0.1 ) { if( std::abs( Vehicle.dizel_engagedeltaomega ) > 0.2 ) { frequency = rsEngageSlippery.m_frequencyoffset + rsEngageSlippery.m_frequencyfactor * std::fabs( Vehicle.dizel_engagedeltaomega ); @@ -6138,7 +6158,7 @@ TDynamicObject::powertrain_sounds::render( TMoverParameters const &Vehicle, doub // motor sounds volume = 0.0; if( ( true == Vehicle.Mains ) - && ( false == Vehicle.dizel_enginestart ) + && ( false == Vehicle.dizel_ignition ) && ( false == motors.empty() ) ) { if( std::fabs( Vehicle.enrot ) > 0.01 ) { diff --git a/DynObj.h b/DynObj.h index d534d69c..0eb826e2 100644 --- a/DynObj.h +++ b/DynObj.h @@ -314,12 +314,14 @@ private: sound_source rsWentylator { sound_placement::engine }; // McZapkie-030302 sound_source engine { sound_placement::engine }; // generally diesel engine sound_source engine_ignition { sound_placement::engine }; // moved from cab + bool engine_state_last { false }; // helper, cached previous state of the engine double engine_volume { 0.0 }; // MC: pomocnicze zeby gladziej silnik buczal sound_source engine_revving { sound_placement::engine }; // youBy float engine_revs_last { -1.f }; // helper, cached rpm of the engine float engine_revs_change { 0.f }; // recent change in engine revolutions sound_source engine_turbo { sound_placement::engine }; double engine_turbo_pitch { 1.0 }; + sound_source oil_pump { sound_placement::engine }; sound_source transmission { sound_placement::engine }; sound_source rsEngageSlippery { sound_placement::engine }; // moved from cab diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index f1056f95..6a2d8bf1 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -164,7 +164,8 @@ enum range { // start method for devices; exclusive enum start { manual, - automatic + automatic, + manualwithautofallback }; // recognized vehicle light locations and types; can be combined enum light { @@ -626,6 +627,19 @@ struct fuel_pump { start start_type { start::manual }; }; +// basic approximation of a fuel pump +// TODO: fuel consumption, optional automatic engine start after activation +struct oil_pump { + + bool is_enabled { false }; // device is allowed/requested to operate + bool is_active { false }; // device is working + start start_type { start::manual }; + float resource_amount { 1.f }; + float pressure_minimum { 0.f }; // lowest acceptable working pressure + float pressure_target { 0.f }; + float pressure_present { 0.f }; +}; + class TMoverParameters { // Ra: wrapper na kod pascalowy, przejmujący jego funkcje Q: 20160824 - juz nie wrapper a klasa bazowa :) public: @@ -913,6 +927,7 @@ public: bool ConverterAllowLocal{ true }; // local device state override (most units don't have this fitted so it's set to true not to intefere) bool ConverterFlag = false; /*! czy wlaczona przetwornica NBMX*/ fuel_pump FuelPump; + oil_pump OilPump; int BrakeCtrlPos = -2; /*nastawa hamulca zespolonego*/ double BrakeCtrlPosR = 0.0; /*nastawa hamulca zespolonego - plynna dla FV4a*/ @@ -1010,7 +1025,8 @@ public: double dizel_engagestate = 0.0; /*sprzeglo skrzyni biegow: 0 - luz, 1 - wlaczone, 0.5 - wlaczone 50% (z poslizgiem)*/ double dizel_engage = 0.0; /*sprzeglo skrzyni biegow: aktualny docisk*/ double dizel_automaticgearstatus = 0.0; /*0 - bez zmiany, -1 zmiana na nizszy +1 zmiana na wyzszy*/ - bool dizel_enginestart = false; /*czy trwa rozruch silnika*/ + bool dizel_startup { false }; // engine startup procedure request indicator + bool dizel_ignition = false; // engine ignition request indicator double dizel_engagedeltaomega = 0.0; /*roznica predkosci katowych tarcz sprzegla*/ double dizel_n_old = 0.0; /*poredkosc na potrzeby obliczen sprzegiel*/ double dizel_Torque = 0.0; /*poredkosc na potrzeby obliczen sprzegiel*/ @@ -1200,6 +1216,7 @@ public: /*--funkcje dla lokomotyw*/ bool DirectionBackward(void);/*! kierunek ruchu*/ bool FuelPumpSwitch( bool State, int const Notify = range::consist ); // fuel pump state toggle + bool OilPumpSwitch( bool State, int const Notify = range::consist ); // oil pump state toggle bool MainSwitch( bool const State, int const Notify = range::consist );/*! wylacznik glowny*/ bool ConverterSwitch( bool State, int const Notify = range::consist );/*! wl/wyl przetwornicy*/ bool CompressorSwitch( bool State, int const Notify = range::consist );/*! wl/wyl sprezarki*/ @@ -1207,7 +1224,8 @@ public: /*-funkcje typowe dla lokomotywy elektrycznej*/ void ConverterCheck( double const Timestep ); // przetwornica void FuelPumpCheck( double const Timestep ); - bool FuseOn(void); //bezpiecznik nadamiary + void OilPumpCheck( double const Timestep ); + bool FuseOn(void); //bezpiecznik nadamiary bool FuseFlagCheck(void); // sprawdzanie flagi nadmiarowego void FuseOff(void); // wylaczenie nadmiarowego double ShowCurrent( int AmpN ); //pokazuje bezwgl. wartosc pradu na wybranym amperomierzu @@ -1238,7 +1256,8 @@ public: bool dizel_AutoGearCheck(void); double dizel_fillcheck(int mcp); double dizel_Momentum(double dizel_fill, double n, double dt); - bool dizel_Update(double dt); + bool dizel_StartupCheck(); + bool dizel_Update(double dt); /* funckje dla wagonow*/ bool LoadingDone(double LSpeed, std::string LoadInit); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 3742a739..3076ec0f 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1554,6 +1554,10 @@ double TMoverParameters::ShowEngineRotation(int VehN) // sprawdzanie przetwornicy void TMoverParameters::ConverterCheck( double const Timestep ) { // TODO: move other converter checks here, to have it all in one place for potential device object + if( ConverterStart == start::automatic ) { + ConverterAllow = Mains; + } + if( ( ConverterAllow ) && ( ConverterAllowLocal ) && ( false == PantPressLockActive ) @@ -1575,11 +1579,56 @@ void TMoverParameters::ConverterCheck( double const Timestep ) { // fuel pump status update void TMoverParameters::FuelPumpCheck( double const Timestep ) { + if( FuelPump.start_type == start::automatic ) { + FuelPump.is_enabled = ( dizel_startup || Mains ); + } FuelPump.is_active = ( ( true == FuelPump.is_enabled ) && ( true == Battery ) ); } +// oil pump status update +void TMoverParameters::OilPumpCheck( double const Timestep ) { + + OilPump.is_active = + ( ( true == Battery ) + && ( OilPump.start_type == start::manual ? ( OilPump.is_enabled ) : + OilPump.start_type == start::automatic ? ( dizel_startup || Mains ) : + OilPump.start_type == start::manualwithautofallback ? ( OilPump.is_enabled || dizel_startup || Mains ) : + false ) ); // shouldn't ever get this far but, eh + + auto const maxrevolutions { + EngineType == DieselEngine ? + dizel_nmax : + DElist[ MainCtrlPosNo ].RPM / 60.0 }; + auto const minpressure { + OilPump.pressure_minimum > 0.f ? + OilPump.pressure_minimum : + 0.1f }; // arbitrary fallback value + auto const maxpressure { 0.65f }; // arbitrary value + + OilPump.pressure_target = ( + false == OilPump.is_active ? 0.f : + enrot > 0.1 ? std::max( minpressure, maxpressure * clamp( enrot / maxrevolutions, 0.0, 1.0 ) ) * OilPump.resource_amount : + minpressure ); + + if( OilPump.pressure_present < OilPump.pressure_target ) { + // TODO: scale change rate from 0.01-0.05 with oil/engine temperature/idle time + OilPump.pressure_present = + std::min( + OilPump.pressure_target, + OilPump.pressure_present + ( enrot > 5.0 ? 0.05 : 0.035 ) * Timestep ); + } + if( OilPump.pressure_present > OilPump.pressure_target ) { + OilPump.pressure_present = + std::max( + OilPump.pressure_target, + OilPump.pressure_present - 0.01 * Timestep ); + } + OilPump.pressure_present = clamp( OilPump.pressure_present, 0.f, 1.5f ); +} + + double TMoverParameters::ShowCurrent(int AmpN) { // Odczyt poboru prądu na podanym amperomierzu switch (EngineType) @@ -2372,13 +2421,38 @@ bool TMoverParameters::FuelPumpSwitch( bool State, int const Notify ) { return ( FuelPump.is_enabled != initialstate ); } +// oil pump state toggle +bool TMoverParameters::OilPumpSwitch( bool State, int const Notify ) { + + if( OilPump.start_type == start::automatic ) { + // automatic pump ignores 'manual' state commands + return false; + } + + bool const initialstate { OilPump.is_enabled }; + + OilPump.is_enabled = State; + + if( Notify != range::local ) { + SendCtrlToNext( + "OilPumpSwitch", + ( OilPump.is_enabled ? 1 : 0 ), + CabNo, + ( Notify == range::unit ? + coupling::control | coupling::permanent : + coupling::control ) ); + } + + return ( OilPump.is_enabled != initialstate ); +} + // ************************************************************************************************* // Q: 20160713 // włączenie / wyłączenie obwodu głownego // ************************************************************************************************* bool TMoverParameters::MainSwitch( bool const State, int const Notify ) { - bool const initialstate { Mains }; + bool const initialstate { Mains || dizel_startup }; if( ( Mains != State ) && ( MainCtrlPosNo > 0 ) ) { @@ -2394,17 +2468,8 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify ) // switch on if( ( EngineType == DieselEngine ) || ( EngineType == DieselElectric ) ) { - - if( true == FuelPump.start_type == start::automatic ) { - // potentially force start of the fuel pump - // TODO: the whole diesel start sequence is a special kind of a mess, clean it up when refactoring - FuelPump.is_enabled = true; - FuelPumpCheck( 0.0 ); - } - if( true == FuelPump.is_active ) { - Mains = true; - dizel_enginestart = true; - } + // launch diesel engine startup procedure + dizel_startup = true; } else { Mains = true; @@ -2412,10 +2477,6 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify ) } else { Mains = false; - if( true == FuelPump.start_type == start::automatic ) { - // if the engine is off, switch off automatic fuel pump - FuelPump.is_enabled = false; - } } if( ( TrainType == dt_EZT ) @@ -2438,11 +2499,10 @@ bool TMoverParameters::MainSwitch( bool const State, int const Notify ) coupling::control | coupling::permanent : coupling::control ) ); } - } } - // else MainSwitch:=false; - return ( Mains != initialstate ); + + return ( ( Mains || dizel_startup ) != initialstate ); } // ************************************************************************************************* @@ -2457,8 +2517,6 @@ bool TMoverParameters::ConverterSwitch( bool State, int const Notify ) { ConverterAllow = State; CS = true; - if (CompressorPower == 2) - CompressorAllow = ConverterAllow; } if( ConverterAllow == true ) { if( Notify != range::local ) { @@ -2488,11 +2546,13 @@ bool TMoverParameters::ConverterSwitch( bool State, int const Notify ) // ************************************************************************************************* bool TMoverParameters::CompressorSwitch( bool State, int const Notify ) { + if( CompressorPower > 1 ) { + // only pay attention if the compressor can be controlled manually + return false; + } + bool CS = false; // Ra: normalnie chyba tak? - // if State=true then - // if ((CompressorPower=2) and (not ConverterAllow)) then - // State:=false; //yB: to juz niepotrzebne - if ((CompressorAllow != State) && (CompressorPower < 2)) + if ( CompressorAllow != State ) { CompressorAllow = State; CS = true; @@ -3094,6 +3154,10 @@ void TMoverParameters::CompressorCheck(double dt) CompressorGovernorLock = false; } + if( CompressorPower == 2 ) { + CompressorAllow = ConverterAllow; + } + if (MaxCompressor - MinCompressor < 0.0001) { // TODO: investigate purpose of this branch and whether it can be removed as it duplicates later code if( ( true == CompressorAllow ) @@ -3124,10 +3188,7 @@ void TMoverParameters::CompressorCheck(double dt) } } else { - if( ( ( CompressorPower == 0 ) - || ( CompressorPower == 3 ) ) - && ( ( EngineType == DieselEngine ) - || ( EngineType == DieselElectric ) ) ) { + if( CompressorPower == 3 ) { // experimental: make sure compressor coupled with diesel engine is always ready for work CompressorAllow = true; } @@ -3167,10 +3228,7 @@ void TMoverParameters::CompressorCheck(double dt) if( Compressor > MaxCompressor ) { // wyłącznik ciśnieniowy jest niezależny od sposobu zasilania // TBD, TODO: don't operate the lock without battery power? - if( ( ( CompressorPower == 0 ) - || ( CompressorPower == 3 ) ) - && ( ( EngineType == DieselEngine ) - || ( EngineType == DieselElectric ) ) ) { + if( CompressorPower == 3 ) { // if the compressor is powered directly by the engine the lock can't turn it off and instead just changes the output if( false == CompressorGovernorLock ) { // emit relay sound when the lock engages (the state change itself is below) and presumably changes where the air goes @@ -3270,42 +3328,29 @@ void TMoverParameters::CompressorCheck(double dt) } if( CompressorFlag ) { - if( ( EngineType == DieselElectric ) - && ( ( CompressorPower == 0 ) - || ( CompressorPower == 3 ) ) ) { + // working compressor adds air to the air reservoir + if( CompressorPower == 3 ) { + // the compressor is coupled with the diesel engine, engine revolutions affect the output if( false == CompressorGovernorLock ) { + auto const enginefactor { ( + EngineType == DieselElectric ? ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM ) : + EngineType == DieselEngine ? ( std::abs( enrot ) / nmax ) : + 1.0 ) }; // shouldn't ever get here but, eh CompressedVolume += CompressorSpeed * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor - * ( DElist[ MainCtrlPos ].RPM / DElist[ MainCtrlPosNo ].RPM ) + * enginefactor * dt; } /* else { - // the lock is active, air is being vented out - CompressedVolume -= 0.1 * dt; - } -*/ - } - else if( ( EngineType == DieselEngine ) - && ( ( CompressorPower == 0 ) - || ( CompressorPower == 3 ) ) ) { - if( false == CompressorGovernorLock ) { - // experimental: compressor coupled with diesel engine, output scaled by current engine rotational speed - CompressedVolume += - CompressorSpeed - * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor - * ( std::abs( enrot ) / nmax ) - * dt; - } -/* - else { - // the lock is active, air is being vented out - CompressedVolume -= 0.1 * dt; + // the lock is active, air is being vented out at arbitrary rate + CompressedVolume -= 0.01 * dt; } */ } else { + // the compressor is a stand-alone device, working at steady pace CompressedVolume += CompressorSpeed * ( 2.0 * MaxCompressor - Compressor ) / MaxCompressor @@ -5780,32 +5825,67 @@ bool TMoverParameters::dizel_AutoGearCheck(void) return OK; } +// performs diesel engine startup procedure; potentially clears startup switch; returns: true if the engine can be started, false otherwise +bool TMoverParameters::dizel_StartupCheck() { + + auto engineisready { true }; // make inital optimistic presumption, then watch the reality crush it + + // test the fuel pump + if( false == FuelPump.is_active ) { + engineisready = false; + if( FuelPump.start_type == start::manual ) { + // with manual pump control startup procedure is done only once per starter switch press + dizel_startup = false; + } + } + // test the oil pump + if( ( false == OilPump.is_active ) + || ( OilPump.pressure_present < OilPump.pressure_minimum ) ) { + engineisready = false; + if( OilPump.start_type == start::manual ) { + // with manual pump control startup procedure is done only once per starter switch press + dizel_startup = false; + } + } + + return engineisready; +} + // ************************************************************************************************* // Q: 20160715 // Aktualizacja stanu silnika // ************************************************************************************************* -bool TMoverParameters::dizel_Update(double dt) -{ +bool TMoverParameters::dizel_Update(double dt) { + + OilPumpCheck( dt ); FuelPumpCheck( dt ); - // potentially automatic engine start after fuel pump was activated - if( ( true == Mains ) - && ( false == FuelPump.is_active ) ) { - // knock out the engine if the fuel pump isn't feeding it - // TBD, TODO: grace period before the engine is starved for fuel and knocked out - MainSwitch( false ); + if( ( true == dizel_startup ) + && ( true == dizel_StartupCheck() ) ) { + dizel_ignition = true; } - if( ( true == dizel_enginestart ) + if( ( true == dizel_ignition ) && ( LastSwitchingTime >= InitialCtrlDelay ) ) { - dizel_enginestart = false; - LastSwitchingTime = 0; + dizel_startup = false; + dizel_ignition = false; + // TODO: split engine and main circuit state indicator in two separate flags + Mains = true; + LastSwitchingTime = 0; enrot = std::max( enrot, 0.35 * ( // TODO: dac zaleznie od temperatury i baterii EngineType == DieselEngine ? dizel_nmin : DElist[ 0 ].RPM / 60.0 ) ); + + } + + if( ( true == Mains ) + && ( false == FuelPump.is_active ) ) { + // knock out the engine if the fuel pump isn't feeding it + // TBD, TODO: grace period before the engine is starved for fuel and knocked out + MainSwitch( false ); } bool DU { false }; @@ -5832,9 +5912,11 @@ double TMoverParameters::dizel_fillcheck(int mcp) && ( MainCtrlPosNo > 0 ) && ( true == FuelPump.is_active ) ) { - if( ( true == dizel_enginestart ) + if( ( true == dizel_ignition ) && ( LastSwitchingTime >= 0.9 * InitialCtrlDelay ) ) { // wzbogacenie przy rozruchu + // NOTE: ignition flag is reset before this code is executed + // TODO: sort this out realfill = 1; } else { @@ -5899,7 +5981,7 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) // wstrzymywanie przy malych obrotach Moment -= dizel_Mstand; } - if (true == dizel_enginestart) + if (true == dizel_ignition) Moment += dizel_Mstand / (0.3 + std::max(0.0, enrot/dizel_nmin)); //rozrusznik dizel_Torque = Moment; @@ -6010,7 +6092,7 @@ double TMoverParameters::dizel_Momentum(double dizel_fill, double n, double dt) } - if ((enrot <= 0) && (!dizel_enginestart)) + if ((enrot <= 0) && (!dizel_ignition)) { Mains = false; enrot = 0; @@ -7680,6 +7762,19 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { start::manual; } + // oil pump + { + std::map starts { + { "Manual", start::manual }, + { "Automatic", start::automatic }, + { "Mixed", start::manualwithautofallback } + }; + auto lookup = starts.find( extract_value( "OilStart", line ) ); + OilPump.start_type = + lookup != starts.end() ? + lookup->second : + start::manual; + } } void TMoverParameters::LoadFIZ_Light( std::string const &line ) { @@ -7833,6 +7928,7 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) { extract_value(hydro_R_MinVel, "R_MinVel", Input, ""); } } + extract_value( OilPump.pressure_minimum, "MinOilPressure", Input, "" ); break; } case DieselElectric: { //youBy @@ -7853,6 +7949,7 @@ void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) { ImaxHi = 2; ImaxLo = 1; } + extract_value( OilPump.pressure_minimum, "OilMinPressure", Input, "" ); break; } case ElectricInductionMotor: { @@ -8132,6 +8229,13 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) Sand = SandCapacity; + // NOTE: for diesel-powered vehicles we automatically convert legacy "main" power source to more accurate "engine" + if( ( CompressorPower == 0 ) + && ( ( EngineType == DieselEngine ) + || ( EngineType == DieselElectric ) ) ) { + CompressorPower = 3; + } + // WriteLog("aa = " + AxleArangement + " " + std::string( Pos("o", AxleArangement)) ); if( ( AxleArangement.find( "o" ) != std::string::npos ) && ( EngineType == ElectricSeriesMotor ) ) { @@ -8574,22 +8678,20 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } + else if (Command == "OilPumpSwitch") { + if( OilPump.start_type == start::manual ) { + // automatic pump ignores 'manual' state commands + OilPump.is_enabled = ( CValue1 == 1 ); + } + OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); + } else if (Command == "MainSwitch") { if (CValue1 == 1) { if( ( EngineType == DieselEngine ) || ( EngineType == DieselElectric ) ) { - if( true == FuelPump.start_type == start::automatic ) { - // potentially force start of the fuel pump - // TODO: the whole diesel start sequence is a special kind of mess, clean it up when refactoring - FuelPump.is_enabled = true; - FuelPumpCheck( 0.0 ); - } - if( true == FuelPump.is_active ) { - Mains = true; - dizel_enginestart = true; - } + dizel_startup = true; } else { Mains = true; @@ -8597,10 +8699,6 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } else { Mains = false; - if( true == FuelPump.start_type == start::automatic ) { - // if the engine is off, switch off automatic fuel pump - FuelPump.is_enabled = false; - } } OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); } diff --git a/Train.cpp b/Train.cpp index 350da7de..60301c0d 100644 --- a/Train.cpp +++ b/Train.cpp @@ -225,6 +225,9 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::fuelpumptoggle, &TTrain::OnCommand_fuelpumptoggle }, { user_command::fuelpumpenable, &TTrain::OnCommand_fuelpumpenable }, { user_command::fuelpumpdisable, &TTrain::OnCommand_fuelpumpdisable }, + { user_command::oilpumptoggle, &TTrain::OnCommand_oilpumptoggle }, + { user_command::oilpumpenable, &TTrain::OnCommand_oilpumpenable }, + { user_command::oilpumpdisable, &TTrain::OnCommand_oilpumpdisable }, { user_command::convertertoggle, &TTrain::OnCommand_convertertoggle }, { user_command::converterenable, &TTrain::OnCommand_converterenable }, { user_command::converterdisable, &TTrain::OnCommand_converterdisable }, @@ -1981,17 +1984,15 @@ void TTrain::OnCommand_linebreakerclose( TTrain *Train, command_data const &Comm if( Train->m_linebreakerstate == 1 ) { return; } // already in the desired state - if( Train->m_linebreakerstate > 1 ) { + if( Train->m_linebreakerstate == 2 ) { // we don't need to start the diesel twice, but the other types (with impulse switch setup) still need to be launched if( ( Train->mvControlled->EngineType != DieselEngine ) && ( Train->mvControlled->EngineType != DieselElectric ) ) { - if( Train->mvControlled->MainSwitch( true ) ) { - // side-effects - Train->mvControlled->ConverterSwitch( ( Train->ggConverterButton.GetValue() > 0.5 ) || ( Train->mvControlled->ConverterStart == start::automatic ) ); - Train->mvControlled->CompressorSwitch( Train->ggCompressorButton.GetValue() > 0.5 ); - // finalize state change of the line breaker - Train->m_linebreakerstate = 1; - } + // try to finalize state change of the line breaker, set the state based on the outcome + Train->m_linebreakerstate = ( + Train->mvControlled->MainSwitch( true ) ? + 1 : + 0 ); } } // on button release reset the closing timer @@ -2038,6 +2039,45 @@ void TTrain::OnCommand_fuelpumpdisable( TTrain *Train, command_data const &Comma } } +void TTrain::OnCommand_oilpumptoggle( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + if( false == Train->mvControlled->OilPump.is_enabled ) { + // turn on + OnCommand_oilpumpenable( Train, Command ); + } + else { + //turn off + OnCommand_oilpumpdisable( Train, Command ); + } + } +} + +void TTrain::OnCommand_oilpumpenable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggOilPumpButton.UpdateValue( 1.0, Train->dsbSwitch ); + + if( true == Train->mvControlled->OilPump.is_enabled ) { return; } // already enabled + + Train->mvControlled->OilPumpSwitch( true ); + } +} + +void TTrain::OnCommand_oilpumpdisable( TTrain *Train, command_data const &Command ) { + + if( Command.action == GLFW_PRESS ) { + // visual feedback + Train->ggOilPumpButton.UpdateValue( 0.0, Train->dsbSwitch ); + + if( false == Train->mvControlled->OilPump.is_enabled ) { return; } // already disabled + + Train->mvControlled->OilPumpSwitch( false ); + } +} + void TTrain::OnCommand_convertertoggle( TTrain *Train, command_data const &Command ) { if( Command.action == GLFW_PRESS ) { @@ -3934,20 +3974,14 @@ bool TTrain::Update( double const Deltatime ) } if( m_linebreakerstate == 2 ) { // for diesels and/or vehicles with toggle switch setup we complete the engine start here - // TBD, TODO: arrange a better way to start the diesel engines if( ( ggMainOnButton.SubModel == nullptr ) || ( ( mvControlled->EngineType == DieselEngine ) || ( mvControlled->EngineType == DieselElectric ) ) ) { - if( mvControlled->MainSwitch( true ) ) { - // side-effects - mvControlled->ConverterSwitch( ( ggConverterButton.GetDesiredValue() > 0.95 ) || ( mvControlled->ConverterStart == start::automatic ) ); - mvControlled->CompressorSwitch( ggCompressorButton.GetDesiredValue() > 0.95 ); - // finalize state change of the line breaker - m_linebreakerstate = 1; - } - else { - m_linebreakerstate = 0; - } + // try to finalize state change of the line breaker, set the state based on the outcome + m_linebreakerstate = ( + mvControlled->MainSwitch( true ) ? + 1 : + 0 ); } } @@ -4364,7 +4398,7 @@ bool TTrain::Update( double const Deltatime ) } if (ggIgnitionKey.SubModel) { - ggIgnitionKey.UpdateValue(mvControlled->dizel_enginestart); + ggIgnitionKey.UpdateValue(mvControlled->dizel_startup); ggIgnitionKey.Update(); } } @@ -4934,6 +4968,7 @@ bool TTrain::Update( double const Deltatime ) ggBatteryButton.Update(); ggFuelPumpButton.Update(); + ggOilPumpButton.Update(); //------ pyScreens.update(); } @@ -5979,6 +6014,7 @@ void TTrain::clear_cab_controls() ggIgnitionKey.Clear(); ggFuelPumpButton.Clear(); + ggOilPumpButton.Clear(); btLampkaPrzetw.Clear(); btLampkaPrzetwB.Clear(); @@ -6249,6 +6285,11 @@ void TTrain::set_cab_controls() { mvOccupied->FuelPump.is_enabled ? 1.0 : 0.0 ); + // oil pump + ggOilPumpButton.PutValue( + mvOccupied->OilPump.is_enabled ? + 1.0 : + 0.0 ); // we reset all indicators, as they're set during the update pass // TODO: when cleaning up break setting indicator state into a separate function, so we can reuse it @@ -6414,6 +6455,7 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "converteroff_sw:", ggConverterOffButton }, { "main_sw:", ggMainButton }, { "fuelpump_sw:", ggFuelPumpButton }, + { "oilpump_sw:", ggOilPumpButton }, { "radio_sw:", ggRadioButton }, { "radiochannel_sw:", ggRadioChannelSelector }, { "radiochannelprev_sw:", ggRadioChannelPrevious }, @@ -6573,6 +6615,12 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con gauge.Load(Parser, DynamicObject, DynamicObject->mdKabina, nullptr, 0.1); gauge.AssignDouble(&mvOccupied->Compressor); } + else if( Label == "oilpress:" ) { + // oil pressure + auto &gauge = Cabine[ Cabindex ].Gauge( -1 ); // pierwsza wolna gałka + gauge.Load( Parser, DynamicObject, DynamicObject->mdKabina, nullptr ); + gauge.AssignFloat( &mvOccupied->OilPump.pressure_present ); + } // yB - dla drugiej sekcji else if (Label == "hvbcurrent1:") { diff --git a/Train.h b/Train.h index b255c784..c9bc1e7b 100644 --- a/Train.h +++ b/Train.h @@ -216,6 +216,9 @@ class TTrain static void OnCommand_fuelpumptoggle( TTrain *Train, command_data const &Command ); static void OnCommand_fuelpumpenable( TTrain *Train, command_data const &Command ); static void OnCommand_fuelpumpdisable( TTrain *Train, command_data const &Command ); + static void OnCommand_oilpumptoggle( TTrain *Train, command_data const &Command ); + static void OnCommand_oilpumpenable( TTrain *Train, command_data const &Command ); + static void OnCommand_oilpumpdisable( TTrain *Train, command_data const &Command ); static void OnCommand_convertertoggle( TTrain *Train, command_data const &Command ); static void OnCommand_converterenable( TTrain *Train, command_data const &Command ); static void OnCommand_converterdisable( TTrain *Train, command_data const &Command ); @@ -406,6 +409,7 @@ public: // reszta może by?publiczna TGauge ggDoorSignallingButton; TGauge ggFuelPumpButton; // fuel pump switch + TGauge ggOilPumpButton; // fuel pump switch TButton btLampkaPoslizg; TButton btLampkaStyczn; diff --git a/command.cpp b/command.cpp index ba7e2d3b..935e2d4c 100644 --- a/command.cpp +++ b/command.cpp @@ -66,6 +66,9 @@ commanddescription_sequence Commands_descriptions = { { "fuelpumptoggle", command_target::vehicle }, { "fuelpumpenable", command_target::vehicle }, { "fuelpumpdisable", command_target::vehicle }, + { "oilpumptoggle", command_target::vehicle }, + { "oilpumpenable", command_target::vehicle }, + { "oilpumpdisable", command_target::vehicle }, { "linebreakertoggle", command_target::vehicle }, { "linebreakeropen", command_target::vehicle }, { "linebreakerclose", command_target::vehicle }, diff --git a/command.h b/command.h index ee5b1f3a..d34f936b 100644 --- a/command.h +++ b/command.h @@ -60,6 +60,9 @@ enum class user_command { fuelpumptoggle, fuelpumpenable, fuelpumpdisable, + oilpumptoggle, + oilpumpenable, + oilpumpdisable, linebreakertoggle, linebreakeropen, linebreakerclose, diff --git a/keyboardinput.cpp b/keyboardinput.cpp index e0c63d02..f4f72199 100644 --- a/keyboardinput.cpp +++ b/keyboardinput.cpp @@ -261,6 +261,12 @@ keyboard_input::default_bindings() { { -1 }, // fuelpumpdisable, { -1 }, + // oilpumptoggle + { GLFW_KEY_F | keymodifier::shift }, + // oilpumpenable, + { -1 }, + // oilpumpdisable, + { -1 }, // linebreakertoggle { GLFW_KEY_M }, // linebreakeropen diff --git a/mouseinput.cpp b/mouseinput.cpp index 582162b2..5b2e6826 100644 --- a/mouseinput.cpp +++ b/mouseinput.cpp @@ -246,6 +246,9 @@ mouse_input::default_bindings() { { "fuelpump_sw:", { user_command::fuelpumptoggle, user_command::none } }, + { "oilpump_sw:", { + user_command::oilpumptoggle, + user_command::none } }, { "main_off_bt:", { user_command::linebreakeropen, user_command::none } }, diff --git a/simulation.cpp b/simulation.cpp index 1d6e2239..978ad2ea 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -542,12 +542,8 @@ state_manager::deserialize_time( cParser &Input, scene::scratch_data &Scratchpad if( true == Global.ScenarioTimeCurrent ) { // calculate time shift required to match scenario time with local clock auto timenow = std::time( 0 ); - auto *localtime = std::localtime( &timenow ); - Global.ScenarioTimeOffset = - clamp_circular( - ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ), - 24 * 60 ) - / 60.f; + auto const *localtime = std::localtime( &timenow ); + Global.ScenarioTimeOffset = ( ( localtime->tm_hour * 60 + localtime->tm_min ) - ( time.wHour * 60 + time.wMinute ) ) / 60.f; } // remaining sunrise and sunset parameters are no longer used, as they're now calculated dynamically diff --git a/translation.h b/translation.h index e7dbf543..2c1fd25b 100644 --- a/translation.h +++ b/translation.h @@ -30,6 +30,7 @@ static std::unordered_map m_cabcontrols = { { "brakeprofiler_sw:", "brake acting speed: rapid" }, { "maxcurrent_sw:", "motor overload relay threshold" }, { "fuelpump_sw:", "fuel pump" }, + { "oilpump_sw:", "oil pump" }, { "main_off_bt:", "line breaker" }, { "main_on_bt:", "line breaker" }, { "security_reset_bt:", "alerter" }, diff --git a/uilayer.cpp b/uilayer.cpp index 115de349..b0a597b3 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -420,10 +420,11 @@ ui_layer::update() { // equipment flags uitextline2 = ( vehicle->MoverParameters->Battery ? "B" : "." ); uitextline2 += ( vehicle->MoverParameters->Mains ? "M" : "." ); - uitextline2 += ( vehicle->MoverParameters->PantRearUp ? ( vehicle->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." );; - uitextline2 += ( vehicle->MoverParameters->PantFrontUp ? ( vehicle->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." );; + uitextline2 += ( vehicle->MoverParameters->PantRearUp ? ( vehicle->MoverParameters->PantRearVolt > 0.0 ? "O" : "o" ) : "." ); + uitextline2 += ( vehicle->MoverParameters->PantFrontUp ? ( vehicle->MoverParameters->PantFrontVolt > 0.0 ? "P" : "p" ) : "." ); uitextline2 += ( vehicle->MoverParameters->PantPressLockActive ? "!" : ( vehicle->MoverParameters->PantPressSwitchActive ? "*" : "." ) ); - uitextline2 += ( vehicle->MoverParameters->FuelPump.is_enabled ? ( vehicle->MoverParameters->FuelPump.is_active ? "F" : "f" ) : "." );; + uitextline2 += ( vehicle->MoverParameters->FuelPump.is_enabled ? ( vehicle->MoverParameters->FuelPump.is_active ? "F" : "f" ) : "." ); + uitextline2 += ( vehicle->MoverParameters->OilPump.is_active ? "O" : ( vehicle->MoverParameters->OilPump.is_enabled ? "o" : "." ) ); uitextline2 += ( false == vehicle->MoverParameters->ConverterAllowLocal ? "-" : ( vehicle->MoverParameters->ConverterAllow ? ( vehicle->MoverParameters->ConverterFlag ? "X" : "x" ) : "." ) ); uitextline2 += ( vehicle->MoverParameters->ConvOvldFlag ? "!" : "." ); uitextline2 += ( false == vehicle->MoverParameters->CompressorAllowLocal ? "-" : ( ( vehicle->MoverParameters->CompressorAllow || vehicle->MoverParameters->CompressorPower > 1 ) ? ( vehicle->MoverParameters->CompressorFlag ? "C" : "c" ) : "." ) ); @@ -698,7 +699,10 @@ ui_layer::update() { VelPrev = vehicle->MoverParameters->Vel; } uitextline2 += "; As=" + to_string( Acc, 2 ); // przyspieszenie wzdłużne +/* uitextline2 += " eAngle=" + to_string( std::cos( vehicle->MoverParameters->eAngle ), 2 ); +*/ + uitextline2 += " oilP=" + to_string( vehicle->MoverParameters->OilPump.pressure_present, 3 ); uitextline3 = "cyl.ham. " + to_string( vehicle->MoverParameters->BrakePress, 2 ) diff --git a/version.h b/version.h index 87f62dea..f1e336ed 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 18 -#define VERSION_MINOR 404 +#define VERSION_MINOR 411 #define VERSION_REVISION 0